Index: lams_learning/web/includes/javascript/presence.js =================================================================== RCS file: /usr/local/cvsroot/lams_learning/web/includes/javascript/presence.js,v diff -u -r1.4.2.5 -r1.4.2.6 --- lams_learning/web/includes/javascript/presence.js 8 Nov 2016 02:43:08 -0000 1.4.2.5 +++ lams_learning/web/includes/javascript/presence.js 24 May 2017 05:42:25 -0000 1.4.2.6 @@ -72,7 +72,8 @@ if (listing.length == 0){ // create listing div var listingDiv = $('
' + + '" onClick="javascript:roster.handleUserClicked(' + + localId + ');" class="presenceListing">' + createPresenceListing(nick, tag) + '
'); @@ -90,62 +91,91 @@ }, // init the connection with server using server URL but with different protocol - presenceWebsocket = new WebSocket(APP_URL.replace('http', 'ws') + 'presenceChatWebsocket?lessonID=' + lessonId + - '&imEnabled=' + presenceImEnabled + '&nickname=' + encodeURIComponent(nickname)); - -// when the server pushes new messages and roster to the learner's browser -presenceWebsocket.onmessage = function(e){ - // create JSON object - var input = JSON.parse(e.data); - if (input.roster) { - roster.updateDisplay(input.roster); - } - - if (input.messages) { - var activeNick = getUserFromTabIndex(presenceChatTabs.tabs('option','active')), - selectedTabTag = nickToTag(activeNick); + presenceWebsocket = new WebSocket(APP_URL.replace('http', 'ws') + 'presenceChatWebsocket?lessonID=' + lessonId + + '&imEnabled=' + presenceImEnabled + + '&nickname=' + encodeURIComponent(nickname)), + presenceWebsocketPingTimeout = null, + presenceWebsocketPingFunc = null; + + presenceWebsocketPingFunc = function(skipPing){ + if (presenceWebsocket.readyState == presenceWebsocket.CLOSING + || presenceWebsocket.readyState == presenceWebsocket.CLOSED){ + location.reload(); + } + + // check and ping every 3 minutes + presenceWebsocketPingTimeout = setTimeout(presenceWebsocketPingFunc, 3*60*1000); + // initial set up does not send ping + if (!skipPing) { + presenceWebsocket.send("ping"); + } + }; + // set up timer for the first time + presenceWebsocketPingFunc(true); + + presenceWebsocket.onclose = function(e){ + // react only on abnormal close + if (e.code === 1006) { + location.reload(); + } + }; + // when the server pushes new messages and roster to the learner's browser + presenceWebsocket.onmessage = function(e){ + // reset ping timer + clearTimeout(presenceWebsocketPingTimeout); + presenceWebsocketPingFunc(true); + + // create JSON object + var input = JSON.parse(e.data); + if (input.roster) { + roster.updateDisplay(input.roster); + } - jQuery.each(input.messages, function(){ - // which tab are we talking about? - var from = this.to ? (this.from == nickname ? this.to : this.from) : groupChatInfo.nick, - lastMessageUid = roster.lastMessageUids[from] || 0; + if (input.messages) { + var activeNick = getUserFromTabIndex(presenceChatTabs.tabs('option','active')), + selectedTabTag = nickToTag(activeNick); - // are the messages new? - if (this.uid > lastMessageUid) { - var tag = nickToTag(from); - if (tag != selectedTabTag) { - var tab = $("#" + tagToTabLabel(tag)); - if (tab.length == 0) { - // no tab opened yet, create it - tab = addTab(from, tag); - } - - // notify of new message - tab.addClass('presenceTabNewMessage'); - if (tag != groupChatInfo.tag) { - $("#" + tagToListing(tag)).addClass('presenceListingNewMessage'); - } - } + jQuery.each(input.messages, function(){ + // which tab are we talking about? + var from = this.to ? (this.from == nickname ? this.to : this.from) : groupChatInfo.nick, + lastMessageUid = roster.lastMessageUids[from] || 0; - roster.lastMessageUids[from] = this.uid; - var messageArea = $("#" + (nickToMessageArea(from))); - messageArea.append(generateMessageHTML(this.from, this.message, this.dateSent)); - messageArea.scrollTop(messageArea.prop('scrollHeight')); - } - }); - } - - // remove conversation tabs with learners who are gone - $('li a', presenceChatTabs).each(function() { - var nick = $(this).text(); - if (nick != groupChatInfo.nick && !roster.users[nick]) { - var tag = $(this).attr('href'); - $(tag).remove(); - $(this).parent().remove(); - presenceChatTabs.tabs('refresh'); + // are the messages new? + if (this.uid > lastMessageUid) { + var tag = nickToTag(from); + if (tag != selectedTabTag) { + var tab = $("#" + tagToTabLabel(tag)); + if (tab.length == 0) { + // no tab opened yet, create it + tab = addTab(from, tag); + } + + // notify of new message + tab.addClass('presenceTabNewMessage'); + if (tag != groupChatInfo.tag) { + $("#" + tagToListing(tag)).addClass('presenceListingNewMessage'); + } + } + + roster.lastMessageUids[from] = this.uid; + var messageArea = $("#" + (nickToMessageArea(from))); + messageArea.append(generateMessageHTML(this.from, this.message, this.dateSent)); + messageArea.scrollTop(messageArea.prop('scrollHeight')); + } + }); } - }); -}; + + // remove conversation tabs with learners who are gone + $('li a', presenceChatTabs).each(function() { + var nick = $(this).text(); + if (nick != groupChatInfo.nick && !roster.users[nick]) { + var tag = $(this).attr('href'); + $(tag).remove(); + $(this).parent().remove(); + presenceChatTabs.tabs('refresh'); + } + }); + }; }); @@ -276,6 +306,10 @@ }; presenceWebsocket.send(JSON.stringify(data)); + + // reset ping timer + clearTimeout(presenceWebsocketPingTimeout); + presenceWebsocketPingFunc(true); } /* ******* Click handlers ******* */