Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20171117.sql
===================================================================
diff -u -redcf26c6dbd1e4ff36858d876e908774abb7910d -r00c630a99ddb827c772bd0fc0d8d903cc0079f7e
--- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20171117.sql (.../patch20171117.sql) (revision edcf26c6dbd1e4ff36858d876e908774abb7910d)
+++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20171117.sql (.../patch20171117.sql) (revision 00c630a99ddb827c772bd0fc0d8d903cc0079f7e)
@@ -26,6 +26,17 @@
REFERENCES lams_kumalive_poll (poll_id) ON DELETE CASCADE ON UPDATE CASCADE
);
+CREATE TABLE lams_kumalive_poll_vote (
+ answer_id BIGINT(20) NOT NULL
+ , user_id BIGINT(20) NOT NULL
+ , vote_date DATETIME
+ , PRIMARY KEY (answer_id, user_id)
+ , CONSTRAINT FK_lams_kumalive_poll_vote_1 FOREIGN KEY (answer_id)
+ REFERENCES lams_kumalive_poll_answer (answer_id) ON DELETE CASCADE ON UPDATE CASCADE
+ , CONSTRAINT FK_lams_kumalive_poll_vote_2 FOREIGN KEY (user_id)
+ REFERENCES lams_user (user_id) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
-- If there were no errors, commit and restore autocommit to on
SET FOREIGN_KEY_CHECKS=0;
COMMIT;
Index: lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumalivePollAnswer.hbm.xml
===================================================================
diff -u -redcf26c6dbd1e4ff36858d876e908774abb7910d -r00c630a99ddb827c772bd0fc0d8d903cc0079f7e
--- lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumalivePollAnswer.hbm.xml (.../KumalivePollAnswer.hbm.xml) (revision edcf26c6dbd1e4ff36858d876e908774abb7910d)
+++ lams_learning/conf/hibernate/mappings/org/lamsfoundation/lams/learning/kumalive/KumalivePollAnswer.hbm.xml (.../KumalivePollAnswer.hbm.xml) (revision 00c630a99ddb827c772bd0fc0d8d903cc0079f7e)
@@ -19,5 +19,11 @@
class="org.lamsfoundation.lams.learning.kumalive.model.KumalivePoll">
+
+
\ No newline at end of file
Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveWebsocketServer.java
===================================================================
diff -u -r8ee91cb1acb876cf1309d37af3b8e08d476a0412 -r00c630a99ddb827c772bd0fc0d8d903cc0079f7e
--- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveWebsocketServer.java (.../KumaliveWebsocketServer.java) (revision 8ee91cb1acb876cf1309d37af3b8e08d476a0412)
+++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/KumaliveWebsocketServer.java (.../KumaliveWebsocketServer.java) (revision 00c630a99ddb827c772bd0fc0d8d903cc0079f7e)
@@ -7,6 +7,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -51,41 +52,29 @@
@ServerEndpoint("/kumaliveWebsocket")
public class KumaliveWebsocketServer {
- private class KumaliveUser {
- private class KumalivePollVote {
- private final Long pollId;
- private final Date time;
- private final int answer;
-
- private KumalivePollVote(Long pollId, Date time, int answer) {
- this.pollId = pollId;
- this.time = time;
- this.answer = answer;
- }
- }
-
+ private static class KumaliveUserDTO {
private final UserDTO userDTO;
private final Session websocket;
private final boolean isTeacher;
private final boolean roleTeacher;
- private KumalivePollVote vote;
+ private KumalivePollVoteDTO vote;
- private KumaliveUser(User user, Session websocket, boolean isTeacher, boolean roleTeacher) {
+ private KumaliveUserDTO(User user, Session websocket, boolean isTeacher, boolean roleTeacher) {
this.userDTO = user.getUserDTO();
this.websocket = websocket;
this.isTeacher = isTeacher;
this.roleTeacher = roleTeacher;
}
}
- private class KumaliveDTO {
+ private static class KumaliveDTO {
private Long id;
private String name;
private UserDTO createdBy;
private boolean raiseHandPrompt;
private final List raisedHand = new CopyOnWriteArrayList<>();
private Integer speaker;
- private final Map learners = new ConcurrentHashMap<>();
+ private final Map learners = new ConcurrentHashMap<>();
private final JSONArray rubrics = new JSONArray();
private KumalivePollDTO poll;
@@ -102,14 +91,31 @@
}
}
- private class KumalivePollDTO {
+ private static class KumalivePollDTO {
+ private final Long pollId;
private final JSONObject pollJSON = new JSONObject();
+ private final List answerIds = new ArrayList();
private final ArrayList> voters = new ArrayList>();
private final JSONArray votersJSON = new JSONArray();
+ private boolean finished = false;
private boolean votesShown = false;
private boolean votersShown = false;
+
+ private KumalivePollDTO(Long pollId) {
+ this.pollId = pollId;
+ }
}
+ private static class KumalivePollVoteDTO {
+ private final Long pollId;
+ private final int answer;
+
+ private KumalivePollVoteDTO(Long pollId, int answer) {
+ this.pollId = pollId;
+ this.answer = answer;
+ }
+ }
+
private static Logger logger = Logger.getLogger(KumaliveWebsocketServer.class);
private static IKumaliveService kumaliveService;
@@ -145,7 +151,7 @@
if (kumalive == null) {
return;
}
- KumaliveUser user = kumalive.learners.remove(login);
+ KumaliveUserDTO user = kumalive.learners.remove(login);
if (user != null) {
Integer userId = user.userDTO.getUserID();
if (kumalive.raisedHand != null) {
@@ -202,6 +208,9 @@
case "startPoll":
startPoll(requestJSON, session);
break;
+ case "votePoll":
+ votePoll(requestJSON, session);
+ break;
case "finishPoll":
finishPoll(requestJSON, session);
break;
@@ -243,7 +252,7 @@
KumalivePoll poll = KumaliveWebsocketServer.getKumaliveService()
.getPollByKumaliveId(kumalive.getKumaliveId());
if (poll != null) {
- KumaliveWebsocketServer.pollToJSON(kumaliveDTO, poll);
+ KumaliveWebsocketServer.fillPollDTO(kumaliveDTO, poll);
}
}
}
@@ -289,7 +298,7 @@
Role.MONITOR);
String role = websocket.getRequestParameterMap().get(AttributeNames.PARAM_ROLE).get(0);
- KumaliveUser learner = kumalive.learners.get(login);
+ KumaliveUserDTO learner = kumalive.learners.get(login);
boolean roleTeacher = isTeacher && !Role.LEARNER.equalsIgnoreCase(role)
&& ("teacher".equalsIgnoreCase(role) || learner == null || learner.roleTeacher);
if (learner != null && !learner.websocket.getId().equals(websocket.getId())) {
@@ -298,14 +307,21 @@
new CloseReason(CloseCodes.NOT_CONSISTENT, "Another websocket for same user was estabilished"));
}
- learner = new KumaliveUser(user, websocket, isTeacher, roleTeacher);
+ learner = new KumaliveUserDTO(user, websocket, isTeacher, roleTeacher);
+ if (kumalive.poll != null) {
+ for (int answerIndex = 0; answerIndex < kumalive.poll.voters.size(); answerIndex++) {
+ if (kumalive.poll.voters.get(answerIndex).contains(learner.userDTO)) {
+ learner.vote = new KumalivePollVoteDTO(kumalive.poll.pollId, answerIndex);
+ }
+ }
+ }
kumalive.learners.put(login, learner);
sendInit(kumalive, learner);
sendRefresh(kumalive);
}
- private void sendInit(KumaliveDTO kumalive, KumaliveUser user) throws JSONException, IOException {
+ private void sendInit(KumaliveDTO kumalive, KumaliveUserDTO user) throws JSONException, IOException {
JSONObject responseJSON = new JSONObject();
responseJSON.put("type", "init");
// Kumalive title
@@ -340,7 +356,7 @@
// each learner's details
JSONArray learnersJSON = new JSONArray();
JSONObject loginsJSON = new JSONObject();
- for (KumaliveUser participant : kumalive.learners.values()) {
+ for (KumaliveUserDTO participant : kumalive.learners.values()) {
UserDTO participantDTO = participant.userDTO;
JSONObject participantJSON = KumaliveWebsocketServer.participantToJSON(participantDTO,
@@ -351,57 +367,59 @@
}
responseJSON.put("learners", learnersJSON);
- JSONArray pollVotesJSON = null;
+ JSONObject pollJSON = null;
// is there a poll running?
if (kumalive.poll != null) {
+ pollJSON = new JSONObject(kumalive.poll.pollJSON.toString());
+
// build votes count JSON
- pollVotesJSON = new JSONArray();
+ JSONArray votesJSON = new JSONArray();
for (int answerIndex = 0; answerIndex < kumalive.poll.voters.size(); answerIndex++) {
List voters = kumalive.poll.voters.get(answerIndex);
// update voters JSON: add only new voters
synchronized (voters) {
- pollVotesJSON.put(voters.size());
- JSONArray votersJSON = kumalive.poll.votersJSON.getJSONArray(answerIndex);
- for (int voterIndex = votersJSON.length(); voterIndex < voters.size(); voterIndex++) {
- votersJSON.put(KumaliveWebsocketServer.participantToJSON(voters.get(voterIndex), null));
+ votesJSON.put(voters.size());
+ JSONArray answerVotersJSON = kumalive.poll.votersJSON.getJSONArray(answerIndex);
+ for (int voterIndex = answerVotersJSON.length(); voterIndex < voters.size(); voterIndex++) {
+ answerVotersJSON.put(KumaliveWebsocketServer.participantToJSON(voters.get(voterIndex), null));
}
}
}
- // put them in response only if teacher released them
- kumalive.poll.pollJSON.put("votes", kumalive.poll.votesShown ? pollVotesJSON : null);
- kumalive.poll.pollJSON.put("voters", kumalive.poll.votersShown ? kumalive.poll.voters : null);
- responseJSON.put("poll", kumalive.poll.pollJSON);
+
+ pollJSON.put("votes", votesJSON);
+ pollJSON.put("voters", kumalive.poll.votersJSON);
}
- // send refresh to everyone
- Long pollId = kumalive.poll == null ? null : kumalive.poll.pollJSON.getLong("id");
- String teacherResponse = null;
String learnerResponse = responseJSON.toString();
- for (KumaliveUser participant : kumalive.learners.values()) {
+ // send extra information to teachers
+ JSONObject teacherResponseJSON = new JSONObject(learnerResponse);
+ teacherResponseJSON.put("logins", loginsJSON);
+ teacherResponseJSON.put("poll", pollJSON);
+ String teacherResponse = teacherResponseJSON.toString();
+ // send refresh to everyone
+ for (KumaliveUserDTO participant : kumalive.learners.values()) {
Basic channel = participant.websocket.getBasicRemote();
- if (participant.isTeacher) {
- // send extra information to teachers
- if (teacherResponse == null) {
- JSONObject teacherResponseJSON = new JSONObject(learnerResponse);
- teacherResponseJSON.put("logins", loginsJSON);
- // add poll votes and voters, if they were not already released and added for all users
- if (kumalive.poll != null) {
- if (!kumalive.poll.votesShown) {
- teacherResponseJSON.getJSONObject("poll").put("votes", pollVotesJSON);
- }
- if (!kumalive.poll.votersShown) {
- teacherResponseJSON.getJSONObject("poll").put("voters", kumalive.poll.votersJSON);
- }
- }
- teacherResponse = teacherResponseJSON.toString();
- }
+ if (participant.roleTeacher) {
channel.sendText(teacherResponse);
- } else if (kumalive.poll == null || kumalive.poll.pollJSON.getBoolean("finished")) {
+ } else if (kumalive.poll == null) {
channel.sendText(learnerResponse);
} else {
- // mark this learner as voted
- responseJSON.getJSONObject("poll").put("voted",
- participant.vote != null && pollId != null && participant.vote.pollId.equals(pollId));
+ JSONObject learnerPollJSON = new JSONObject(pollJSON.toString());
+ boolean voted = participant.vote != null && kumalive.poll.pollId != null
+ && participant.vote.pollId.equals(kumalive.poll.pollId);
+ // put them in response only if teacher released them and user voted
+ if (!kumalive.poll.votesShown || (!voted && !kumalive.poll.finished)) {
+ learnerPollJSON.remove("votes");
+ }
+ if (!kumalive.poll.votersShown || (!voted && !kumalive.poll.finished)) {
+ learnerPollJSON.remove("voters");
+ }
+ if (voted) {
+ // mark this learner as voted
+ learnerPollJSON.put("voted", participant.vote.answer);
+ }
+ responseJSON.put("poll", learnerPollJSON);
+
channel.sendText(responseJSON.toString());
}
}
@@ -606,7 +624,7 @@
KumalivePoll poll = KumaliveWebsocketServer.getKumaliveService().startPoll(kumalive.id,
pollJSON.getString("name"), pollJSON.getJSONArray("answers"));
if (poll != null) {
- KumaliveWebsocketServer.pollToJSON(kumalive, poll);
+ KumaliveWebsocketServer.fillPollDTO(kumalive, poll);
}
if (logger.isDebugEnabled()) {
logger.debug("Teacher " + userId + " started poll " + poll.getPollId() + " in Kumalive " + kumalive.id);
@@ -617,6 +635,47 @@
/**
* Tell learners that the teacher started a poll
*/
+ private void votePoll(JSONObject requestJSON, Session websocket) throws IOException, JSONException {
+ Integer organisationId = Integer
+ .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_ORGANISATION_ID).get(0));
+ User user = getUser(websocket);
+ Integer userId = user.getUserId();
+
+ if (!KumaliveWebsocketServer.getSecurityService().hasOrgRole(organisationId, userId,
+ new String[] { Role.LEARNER }, "kumalive poll vote", false)) {
+ String warning = "User " + userId + " is not a learner of organisation " + organisationId;
+ logger.warn(warning);
+ return;
+ }
+
+ KumaliveDTO kumalive = kumalives.get(organisationId);
+ if (kumalive.poll == null || kumalive.poll.finished) {
+ logger.warn("Learner " + userId + " tried to vote but a poll is not started in Kumalive " + kumalive.id);
+ return;
+ }
+ KumaliveUserDTO learnerDTO = kumalive.learners.get(user.getLogin());
+ if (learnerDTO.vote != null && learnerDTO.vote.pollId.equals(kumalive.poll.pollId)) {
+ logger.warn("Learner " + userId + " tried to vote for poll " + kumalive.poll.pollId
+ + " but he already voted in Kumalive " + kumalive.id);
+ return;
+ }
+
+ Integer answerIndex = requestJSON.getInt("answerIndex");
+ Long answerId = kumalive.poll.answerIds.get(answerIndex);
+ KumaliveWebsocketServer.getKumaliveService().saveVote(answerId, userId);
+ learnerDTO.vote = new KumalivePollVoteDTO(kumalive.poll.pollId, answerIndex);
+ kumalive.poll.voters.get(answerIndex).add(learnerDTO.userDTO);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "Learner " + userId + " voted in poll " + kumalive.poll.pollId + " in Kumalive " + kumalive.id);
+ }
+ sendRefresh(kumalive);
+ }
+
+ /**
+ * Tell learners that the teacher started a poll
+ */
private void finishPoll(JSONObject requestJSON, Session websocket) throws IOException, JSONException {
Integer organisationId = Integer
.valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_ORGANISATION_ID).get(0));
@@ -635,6 +694,7 @@
KumaliveWebsocketServer.getKumaliveService().finishPoll(pollId);
KumaliveDTO kumalive = kumalives.get(organisationId);
+ kumalive.poll.finished = true;
kumalive.poll.pollJSON.put("finished", true);
if (logger.isDebugEnabled()) {
@@ -686,7 +746,7 @@
KumaliveDTO kumalive = kumalives.get(organisationId);
KumaliveWebsocketServer.getKumaliveService().finishKumalive(kumalive.id);
kumalives.remove(organisationId);
- for (KumaliveUser participant : kumalive.learners.values()) {
+ for (KumaliveUserDTO participant : kumalive.learners.values()) {
participant.websocket.getBasicRemote().sendText("{ \"type\" : \"finish\"}");
}
@@ -712,16 +772,41 @@
return participantJSON;
}
- private static void pollToJSON(KumaliveDTO kumaliveDTO, KumalivePoll poll) throws JSONException {
- kumaliveDTO.poll.pollJSON.put("id", poll.getPollId());
- kumaliveDTO.poll.pollJSON.put("name", poll.getName());
+ private static void fillPollDTO(KumaliveDTO kumalive, KumalivePoll poll) throws JSONException {
+ KumalivePollDTO pollDTO = new KumalivePollDTO(poll.getPollId());
+ pollDTO.pollJSON.put("id", poll.getPollId());
+ pollDTO.pollJSON.put("name", poll.getName());
JSONArray answersJSON = new JSONArray();
for (KumalivePollAnswer answer : poll.getAnswers()) {
answersJSON.put(answer.getName());
- kumaliveDTO.poll.voters.add(Collections.synchronizedList(new LinkedList()));
- kumaliveDTO.poll.votersJSON.put(new JSONArray());
+ pollDTO.answerIds.add(answer.getAnswerId());
+
+ List answerVoters = Collections.synchronizedList(new LinkedList());
+ pollDTO.voters.add(answerVoters);
+ JSONArray answerVotersJSON = new JSONArray();
+ pollDTO.votersJSON.put(answerVotersJSON);
+ if (answer.getVotes() != null) {
+ for (Entry vote : answer.getVotes().entrySet()) {
+ Integer userId = vote.getKey();
+ UserDTO userDTO = null;
+ for (KumaliveUserDTO learner : kumalive.learners.values()) {
+ if (userId.equals(learner.userDTO.getUserID())) {
+ userDTO = learner.userDTO;
+ break;
+ }
+ }
+ if (userDTO == null) {
+ User user = (User) KumaliveWebsocketServer.getUserManagementService().findById(User.class,
+ userId);
+ userDTO = user.getUserDTO();
+ }
+ answerVoters.add(userDTO);
+ answerVotersJSON.put(KumaliveWebsocketServer.participantToJSON(userDTO, null));
+ }
+ }
}
- kumaliveDTO.poll.pollJSON.put("answers", answersJSON);
+ pollDTO.pollJSON.put("answers", answersJSON);
+ kumalive.poll = pollDTO;
}
private static IKumaliveService getKumaliveService() {
Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumalivePollAnswer.java
===================================================================
diff -u -redcf26c6dbd1e4ff36858d876e908774abb7910d -r00c630a99ddb827c772bd0fc0d8d903cc0079f7e
--- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumalivePollAnswer.java (.../KumalivePollAnswer.java) (revision edcf26c6dbd1e4ff36858d876e908774abb7910d)
+++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/model/KumalivePollAnswer.java (.../KumalivePollAnswer.java) (revision 00c630a99ddb827c772bd0fc0d8d903cc0079f7e)
@@ -23,6 +23,8 @@
package org.lamsfoundation.lams.learning.kumalive.model;
import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
public class KumalivePollAnswer implements Serializable {
@@ -32,6 +34,7 @@
private KumalivePoll poll;
private Short orderId;
private String name;
+ private Map votes;
public KumalivePollAnswer() {
}
@@ -73,4 +76,12 @@
public void setName(String name) {
this.name = name;
}
+
+ public Map getVotes() {
+ return votes;
+ }
+
+ public void setVotes(Map votes) {
+ this.votes = votes;
+ }
}
\ No newline at end of file
Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/IKumaliveService.java
===================================================================
diff -u -ra6756ff12e2b1eaa3c06a2456c87daea872397f2 -r00c630a99ddb827c772bd0fc0d8d903cc0079f7e
--- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/IKumaliveService.java (.../IKumaliveService.java) (revision a6756ff12e2b1eaa3c06a2456c87daea872397f2)
+++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/IKumaliveService.java (.../IKumaliveService.java) (revision 00c630a99ddb827c772bd0fc0d8d903cc0079f7e)
@@ -66,4 +66,6 @@
KumalivePoll startPoll(Long kumaliveId, String name, JSONArray answersJSON) throws JSONException;
void finishPoll(Long pollId) throws JSONException;
+
+ void saveVote(Long answerId, Integer userId);
}
\ No newline at end of file
Index: lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/KumaliveService.java
===================================================================
diff -u -ra6756ff12e2b1eaa3c06a2456c87daea872397f2 -r00c630a99ddb827c772bd0fc0d8d903cc0079f7e
--- lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/KumaliveService.java (.../KumaliveService.java) (revision a6756ff12e2b1eaa3c06a2456c87daea872397f2)
+++ lams_learning/src/java/org/lamsfoundation/lams/learning/kumalive/service/KumaliveService.java (.../KumaliveService.java) (revision 00c630a99ddb827c772bd0fc0d8d903cc0079f7e)
@@ -31,6 +31,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -558,7 +559,7 @@
KumalivePoll poll = new KumalivePoll(kumalive, name);
kumaliveDAO.insert(poll);
- Set answers = new HashSet<>();
+ Set answers = new LinkedHashSet<>();
for (Short answerIndex = 0; answerIndex < answersJSON.length(); answerIndex++) {
String answerName = answersJSON.getString(answerIndex.intValue());
KumalivePollAnswer answer = new KumalivePollAnswer(poll, answerIndex, answerName);
@@ -575,7 +576,28 @@
return poll;
}
+ /**
+ * Store a user's vote for a poll
+ */
@Override
+ public void saveVote(Long answerId, Integer userId) {
+ KumalivePollAnswer answer = (KumalivePollAnswer) kumaliveDAO.find(KumalivePollAnswer.class, answerId);
+ if (answer.getVotes().containsKey(userId)) {
+ logger.warn("Learner " + userId + " tried to vote for answer ID " + answerId + " but he already voted");
+ return;
+ }
+ answer.getVotes().put(userId, new Date());
+ kumaliveDAO.update(answer);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Learner " + userId + " voted for answer ID " + answerId);
+ }
+ }
+
+ /**
+ * Finishes a poll, i.e. prevents learners from voting
+ */
+ @Override
public void finishPoll(Long pollId) throws JSONException {
KumalivePoll poll = (KumalivePoll) kumaliveDAO.find(KumalivePoll.class, pollId);
if (poll.getFinishDate() != null) {
Index: lams_learning/web/includes/javascript/kumalive.js
===================================================================
diff -u -ra6756ff12e2b1eaa3c06a2456c87daea872397f2 -r00c630a99ddb827c772bd0fc0d8d903cc0079f7e
--- lams_learning/web/includes/javascript/kumalive.js (.../kumalive.js) (revision a6756ff12e2b1eaa3c06a2456c87daea872397f2)
+++ lams_learning/web/includes/javascript/kumalive.js (.../kumalive.js) (revision 00c630a99ddb827c772bd0fc0d8d903cc0079f7e)
@@ -191,6 +191,7 @@
} else {
$('#raiseHandButton').click(raiseHand);
$('#downHandButton').click(downHand);
+ $('#pollRunVoteButton').click(votePoll);
}
// set dialog name
@@ -344,41 +345,24 @@
// init poll fields or make them read only after voting
if (poll.id != pollId || (poll.finished && $('#pollRunVoteButton').is(':visible'))) {
- pollId = poll.id;
- $('#pollRun button').hide();
- $('#pollRunQuestion').text(poll.name);
- var radioList = $('#pollRunAnswerRadios').empty(),
- answerList = $('#pollRunAnswerList').empty();
- // teachers can't vote; learner can't vote twice; learner can't vote for finished poll
- if (roleTeacher || poll.voted || poll.finished) {
- // build simple list of answers
- $.each(poll.answers, function(index, answer){
- var answerElement = $('').addClass('list-group-item').text(pollAnswerBullets[index] + ') ' + answer)
- .appendTo(answerList);
- if (poll.votes) {
- // show votes if user is teacher or votes were released
- $('').addClass('badge').text(poll.votes[index]).appendTo(answerElement);
- }
- });
- $('#pollRunAnswerList').show();
- // extra options for teacher
- if (roleTeacher) {
- if (poll.finished) {
- $('#pollRunCloseButton').show();
- } else {
- $('#pollRunFinishButton').show();
- }
+ initPoll(poll);
+ }
+ if (poll.votes) {
+ // show votes if user is teacher or votes were released
+ $.each(poll.votes, function(index, count) {
+ var answerElement = $('#pollAnswer' + index),
+ badge = $('.badge', answerElement);
+ // missing badge means that votes were made available just now
+ if (badge.length === 0) {
+ badge = $('').addClass('badge').appendTo(answerElement);
}
- } else {
- // learner can vote, build radio buttons
- $.each(poll.answers, function(index, answer){
- $('#pollRunAnswerRadioTemplate').clone().attr('id', null).appendTo(radioList)
- .find('label').append($('').text(pollAnswerBullets[index] + ') ' + answer))
- .find('input').val(index);
- });
- $('#pollRunVoteButton').show();
- }
+ badge.text(count);
+ });
}
+ if (poll.voted != null) {
+ // highlight the answer user voted for
+ $('#pollAnswer' + poll.voted).addClass('active');
+ }
}
/**
@@ -708,6 +692,49 @@
}
/**
+ * Create poll widgets: answer list, radio buttons etc.
+ */
+function initPoll(poll) {
+ pollId = poll.id;
+ $('#pollRun button').hide();
+ $('#pollRunQuestion').text(poll.name);
+ var radioList = $('#pollRunAnswerRadios').empty(),
+ answerList = $('#pollRunAnswerList').empty();
+
+ // teachers can't vote; learner can't vote twice; learner can't vote for finished poll
+ if (roleTeacher || (poll.voted != null) || poll.finished) {
+ // build simple list of answers
+ $.each(poll.answers, function(index, answer){
+ var answerElement = $('').addClass('list-group-item').attr('id', 'pollAnswer' + index)
+ .text(pollAnswerBullets[index] + ') ' + answer)
+ .appendTo(answerList);
+ if (poll.votes) {
+ // show votes if user is teacher or votes were released
+ $('').addClass('badge').text(poll.votes[index]).appendTo(answerElement);
+ }
+ });
+ $('#pollRunAnswerList').show();
+ // extra options for teacher
+
+ if (roleTeacher) {
+ if (poll.finished) {
+ $('#pollRunCloseButton').show();
+ } else {
+ $('#pollRunFinishButton').show();
+ }
+ }
+ } else {
+ // learner can vote, build radio buttons
+ $.each(poll.answers, function(index, answer){
+ $('#pollRunAnswerRadioTemplate').clone().attr('id', null).appendTo(radioList)
+ .find('label').append($('').text(pollAnswerBullets[index] + ') ' + answer))
+ .find('input').val(index);
+ });
+ $('#pollRunVoteButton').show();
+ }
+}
+
+/**
* Create a poll with parameters set up in form
*/
function startPoll(){
@@ -794,6 +821,21 @@
}
/**
+ * Send vote to the server
+ */
+function votePoll() {
+ var checkedAnswer = $('#pollRunAnswerRadios input[name="pollAnswer"]:checked');
+ if (checkedAnswer.length !== 1) {
+ return;
+ }
+ pollId = null;
+ kumaliveWebsocket.send(JSON.stringify({
+ 'type' : 'votePoll',
+ 'answerIndex' : checkedAnswer.val()
+ }));
+}
+
+/**
* Prevent learners from voting
*/
function finishPoll() {
Index: lams_learning/web/kumalive/kumalive.jsp
===================================================================
diff -u -ra6756ff12e2b1eaa3c06a2456c87daea872397f2 -r00c630a99ddb827c772bd0fc0d8d903cc0079f7e
--- lams_learning/web/kumalive/kumalive.jsp (.../kumalive.jsp) (revision a6756ff12e2b1eaa3c06a2456c87daea872397f2)
+++ lams_learning/web/kumalive/kumalive.jsp (.../kumalive.jsp) (revision 00c630a99ddb827c772bd0fc0d8d903cc0079f7e)
@@ -148,7 +148,7 @@
-
+