Index: lams_tool_scratchie/web/pages/learning/learning.jsp
===================================================================
diff -u -r281e19ba98aa6bf38fc1f25507a9098304d668fb -r705c0f72b765849974bfa0d9f8b04797619e8da7
--- lams_tool_scratchie/web/pages/learning/learning.jsp (.../learning.jsp) (revision 281e19ba98aa6bf38fc1f25507a9098304d668fb)
+++ lams_tool_scratchie/web/pages/learning/learning.jsp (.../learning.jsp) (revision 705c0f72b765849974bfa0d9f8b04797619e8da7)
@@ -1,6 +1,7 @@
<%@ include file="/common/taglibs.jsp"%>
+
<%-- param has higher level for request attribute --%>
@@ -10,6 +11,9 @@
+
+
+
@@ -23,7 +27,19 @@
-
+
@@ -83,6 +99,11 @@
}
});
+ // hide Finish button for non-leaders until leader finishes
+ if (${hideFinishButton}) {
+ $("#finishButton").hide();
+ }
+
<%-- Connect to command websocket only if it is learner UI --%>
// command websocket stuff for refreshing
@@ -272,46 +293,11 @@
(((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0);
}
- //boolean to indicate whether ok dialog is still ON so that autosave can't be run
- var isWaitingForConfirmation = ${isTimeLimitEnabled && isTimeLimitNotLaunched};
- //time limit feature
-
- $(document).ready(function(){
-
- //show timelimit-start-dialog in order to start countdown
- if (${isTimeLimitNotLaunched}) {
-
- //show confirmation dialog
- $.blockUI({
- message: $('#timelimit-start-dialog'),
- css: { width: '325px', height: '120px'},
- overlayCSS: { opacity: '.98'}
- });
-
- //once OK button pressed start countdown
- $('#timelimit-start-ok').click(function() {
-
- //store date when user has started activity with time limit
- $.ajax({
- async: true,
- url: '',
- data: 'sessionMapID=${sessionMapID}',
- type: 'post'
- });
-
- $.unblockUI();
- displayCountdown();
- isWaitingForConfirmation = false;
- });
-
- } else {
- displayCountdown();
- }
-
- });
+
+ // time limit feature
- function displayCountdown(){
+ function displayCountdown(secondsLeft){
var countdown = ''
$.blockUI({
message: countdown,
@@ -329,30 +315,123 @@
});
$('#countdown').countdown({
- until: '+${secondsLeft}S',
+ until: '+' + secondsLeft +'S',
format: 'hMS',
compact: true,
+ alwaysExpire : true,
onTick: function(periods) {
- //check for 30 seconds
- if ((periods[4] == 0) && (periods[5] == 0) && (periods[6] <= 30)) {
- $('#countdown').css('color', '#FF3333');
- }
+ // check for 30 seconds or less and display timer in red
+ var secondsLeft = $.countdown.periodsToSeconds(periods);
+ if (secondsLeft <= 30) {
+ $(this).addClass('countdown-timeout');
+ } else {
+ $(this).removeClass('countdown-timeout');
+ }
},
onExpiry: function(periods) {
- $.blockUI({ message: '
' });
+ $.blockUI({ message: '
' });
- setTimeout(
- function() {
- finish(true);
- },
- 4000
- );
+ setTimeout(function() {
+ if (${isUserLeader}) {
+ finish(true);
+ } else {
+ location.reload();
+ }
+ }, 4000);
},
description: "
"
});
}
-
+
+ //init the connection with server using server URL but with different protocol
+ var scratchieWebsocketInitTime = Date.now(),
+ scratchieWebsocket = new WebSocket(''.replace('http', 'ws')
+ + 'learningWebsocket?toolSessionID=' + ${toolSessionID} + '&toolContentID=' + ${scratchie.contentId}),
+ scratchieWebsocketPingTimeout = null,
+ scratchieWebsocketPingFunc = null;
+
+ scratchieWebsocket.onclose = function(e) {
+ // react only on abnormal close
+ if (e.code === 1006 &&
+ Date.now() - scratchieWebsocketInitTime > 1000) {
+ location.reload();
+ }
+ };
+
+ scratchieWebsocketPingFunc = function(skipPing){
+ if (scratchieWebsocket.readyState == scratchieWebsocket.CLOSING
+ || scratchieWebsocket.readyState == scratchieWebsocket.CLOSED){
+ return;
+ }
+
+ // check and ping every 3 minutes
+ scratchieWebsocketPingTimeout = setTimeout(scratchieWebsocketPingFunc, 3*60*1000);
+ // initial set up does not send ping
+ if (!skipPing) {
+ scratchieWebsocket.send("ping");
+ }
+ };
+
+ // set up timer for the first time
+ scratchieWebsocketPingFunc(true);
+
+ // run when the server pushes new reports and vote statistics
+ scratchieWebsocket.onmessage = function(e) {
+ // create JSON object
+ var input = JSON.parse(e.data);
+ if (input.pageRefresh) {
+ location.reload();
+ return;
+ }
+
+ if (input.clearTimer == true) {
+ // teacher stopped the timer, destroy it
+ $('#countdown').countdown('destroy').remove();
+ } else if (input.secondsLeft){
+ // teacher updated the timer
+ var secondsLeft = +input.secondsLeft,
+ counterInitialised = $('#countdown').length > 0;
+
+ if (counterInitialised) {
+ // just set the new time
+ $('#countdown').countdown('option', 'until', secondsLeft + 'S');
+ } else if (secondsLeft){
+ if (${isScratchingFinished}) {
+ // teacher gave extra time, reload to enable scratching again
+ location.reload();
+ return;
+ }
+ // initialise the timer
+ displayCountdown(secondsLeft);
+ }
+ } else if (${not isUserLeader}){
+ // reflect the leader's choices
+ $.each(input, function(itemUid, options) {
+ $.each(options, function(optionUid, optionProperties){
+
+ if (optionProperties.isVSA) {
+ var answer = optionUid;
+ optionUid = hashCode(optionUid);
+
+ //check if such image exists, create it otherwise
+ if ($('#image-' + itemUid + '-' + optionUid).length == 0) {
+ paintNewVsaAnswer(eval(itemUid), answer);
+ }
+ }
+
+ scratchImage(itemUid, optionUid, optionProperties.isCorrect);
+ });
+ });
+ }
+
+ // reset ping timer
+ clearTimeout(scratchieWebsocketPingTimeout);
+ scratchieWebsocketPingFunc(true);
+ };
+
+
+
//autosave feature
var autosaveInterval = "60000"; // 60 seconds interval