LT-107: Add countdown dialog

- Remove ui from meteor-stale-session package
This commit is contained in:
Aysel Afsar 2016-02-09 22:16:37 -05:00
parent d18a66d513
commit 5ec3cace94
14 changed files with 158 additions and 74 deletions

View File

@ -71,8 +71,6 @@ meteor-base@1.0.1
meteor-platform@1.2.3 meteor-platform@1.2.3
minifiers@1.1.7 minifiers@1.1.7
minimongo@1.0.10 minimongo@1.0.10
mizzao:build-fetcher@0.2.0
mizzao:jquery-ui@1.11.4
mobile-experience@1.0.1 mobile-experience@1.0.1
mobile-status-bar@1.0.6 mobile-status-bar@1.0.6
momentjs:moment@2.11.2 momentjs:moment@2.11.2

View File

@ -18,5 +18,6 @@
</div> </div>
{{/if}} {{/if}}
</div> </div>
{{> timeoutCountdownDialog}}
{{> yield}} {{> yield}}
</template> </template>

View File

@ -11,3 +11,31 @@ Template.layoutLesionTracker.helpers({
return Meteor.user().profile.fullName; return Meteor.user().profile.fullName;
} }
}); });
Template.layoutLesionTracker.onCreated(function() {
// Show countdown dialog
var handle;
$(document).on('TriggerOpenTimeoutCountdownDialog', function (e, leftTime) {
// TODO: Show modal dialog
handle = setInterval(function() {
leftTime --;
// Set countdownDialogLeftTime session
Session.set("countdownDialogLeftTime", leftTime);
// Show dialog
if ($("#timeoutCountdownDialog").css("display") == "none") {
$("#timeoutCountdownDialog").css("display", "block");
}
}, 1000);
});
$(document).on('TriggerCloseTimeoutCountdownDialog', function (e) {
$("#timeoutCountdownDialog").css("display", "none");
if (handle) {
clearInterval(handle);
// Close the dialog
$("#timeoutCountdownDialog").css("display", "none");
}
});
});

View File

@ -0,0 +1,10 @@
<template name="timeoutCountdownDialog">
<div id="timeoutCountdownDialog">
<div class="dialogHeader">
<h5>Session is about to expire!</h5>
</div>
<div class="dialogContent">
<p>You will be log out in {{leftTime}} {{secondsText}}.</p>
</div>
</div>
</template>

View File

@ -0,0 +1,9 @@
Template.timeoutCountdownDialog.helpers({
leftTime: function(e) {
return Session.get("countdownDialogLeftTime");
},
secondsText: function() {
return Session.get("countdownDialogLeftTime") > 1? "seconds": "second";
}
});

View File

@ -0,0 +1,15 @@
#timeoutCountdownDialog
display: none
position: absolute
top: 0
bottom: 0
left: 0
right: 0
margin: auto
width: 20%
height: 15%
z-index: 100
border-radius: 5px
padding: 10px 20px 10px 20px
background-color: rgba(255,255,255,1)
outline: none

View File

@ -79,6 +79,10 @@ Package.onUse(function(api) {
api.addFiles('client/components/nonTargetResponseDialog/nonTargetResponseDialog.styl', 'client'); api.addFiles('client/components/nonTargetResponseDialog/nonTargetResponseDialog.styl', 'client');
api.addFiles('client/components/nonTargetResponseDialog/nonTargetResponseDialog.js', 'client'); api.addFiles('client/components/nonTargetResponseDialog/nonTargetResponseDialog.js', 'client');
api.addFiles('client/components/timeoutCountdownDialog/timeoutCountdownDialog.html', 'client');
api.addFiles('client/components/timeoutCountdownDialog/timeoutCountdownDialog.styl', 'client');
api.addFiles('client/components/timeoutCountdownDialog/timeoutCountdownDialog.js', 'client');
api.addFiles('client/components/timepointTextDialog/timepointTextDialog.html', 'client'); api.addFiles('client/components/timepointTextDialog/timepointTextDialog.html', 'client');
api.addFiles('client/components/timepointTextDialog/timepointTextDialog.styl', 'client'); api.addFiles('client/components/timepointTextDialog/timepointTextDialog.styl', 'client');

View File

@ -9,74 +9,84 @@
var heartbeatInterval = Meteor.settings && Meteor.settings.public && Meteor.settings.public.staleSessionHeartbeatInterval || (3*60*1000); // 3mins var heartbeatInterval = Meteor.settings && Meteor.settings.public && Meteor.settings.public.staleSessionHeartbeatInterval || (3*60*1000); // 3mins
var activityEvents = Meteor.settings && Meteor.settings.public && Meteor.settings.public.staleSessionActivityEvents || 'mousemove click keydown'; var activityEvents = Meteor.settings && Meteor.settings.public && Meteor.settings.public.staleSessionActivityEvents || 'mousemove click keydown';
var inactivityTimeout = Meteor.settings && Meteor.settings.public && Meteor.settings.public.staleSessionInactivityTimeout || (30*60*1000); // 30mins var inactivityTimeout = Meteor.settings && Meteor.settings.public && Meteor.settings.public.staleSessionInactivityTimeout || (30*60*1000); // 30mins
var countdownDialogTime = Meteor.settings && Meteor.settings.public && Meteor.settings.public.countdownDialogTime || (15*1000); // 30second
var showCountdownDialog = Meteor.settings && Meteor.settings.public && Meteor.settings.public.showCountdownDialog || true; var dialogTimeout = Meteor.settings && Meteor.settings.public && Meteor.settings.public.dialogTimeout || (30*1000); // 30secs
var showCountdownDialog = Meteor.settings && Meteor.settings.public && Meteor.settings.public.showCountdownDialog || false;
var countdownHeartbeatInterval = (heartbeatInterval < dialogTimeout)? heartbeatInterval : dialogTimeout;
var activityDetected = false; var activityDetected = false;
var activityDetectedTime = new Date(); var lastActivityDetectedTime = new Date();
var dialogIsOpen = false;
Meteor.startup(function() { Meteor.startup(function() {
// Add countdown dialog to body
$("body").append('<div id="staleSessionCountdownModal" title="Session will expire!"></div>');
//Initialize the dialog
$("#staleSessionCountdownModal").dialog({
autoOpen: false,
open: function(){
$('.ui-widget-overlay').bind('click',function(){
$('#staleSessionCountdownModal').dialog('close');
});
}
});
// //
// periodically send a heartbeat if activity has been detected within the interval // periodically send a heartbeat if activity has been detected within the interval
// //
if (showCountdownDialog) {
Meteor.setInterval(function() {
if (Meteor.userId()) {
if (activityDetected) {
Meteor.call('heartbeat', function(error, heartbeatTime) {
lastActivityDetectedTime = heartbeatTime;
activityDetected = false;
// Event to close dialog
$.event.trigger('TriggerCloseTimeoutCountdownDialog');
dialogIsOpen = false;
});
} else {
var overdueTimestamp = new Date().getTime() - lastActivityDetectedTime;
// Ignore min differences
overdueTimestamp = overdueTimestamp - (overdueTimestamp % 1000);
console.log(overdueTimestamp);
var startTime = inactivityTimeout - dialogTimeout;
if (overdueTimestamp <= inactivityTimeout) {
var nextIntervalTime = overdueTimestamp + countdownHeartbeatInterval;
if (nextIntervalTime <= inactivityTimeout && nextIntervalTime >= startTime) {
if (Math.abs(startTime - overdueTimestamp) <= Math.abs(nextIntervalTime - startTime) && !dialogIsOpen) {
// Open dialog
var leftTime = Math.round((inactivityTimeout - overdueTimestamp) / 1000);
$.event.trigger('TriggerOpenTimeoutCountdownDialog', leftTime);
dialogIsOpen = true;
}
} else {
// Event to close dialog
$.event.trigger('TriggerCloseTimeoutCountdownDialog');
dialogIsOpen = false;
}
} else {
// Event to close dialog
$.event.trigger('TriggerCloseTimeoutCountdownDialog');
dialogIsOpen = false;
}
}
} else {
// Event to close dialog
$.event.trigger('TriggerCloseTimeoutCountdownDialog');
dialogIsOpen = false;
}
}, countdownHeartbeatInterval);
} else{
Meteor.setInterval(function() { Meteor.setInterval(function() {
if (Meteor.userId() && activityDetected) { if (Meteor.userId() && activityDetected) {
Meteor.call('heartbeat'); Meteor.call('heartbeat');
activityDetected = false; activityDetected = false;
} }
}, heartbeatInterval); }, heartbeatInterval);
// Detect the time when countdown dialog will be shown
if (showCountdownDialog) {
Meteor.setInterval(function() {
if (!activityDetected) {
var lastHeartbeatTime = activityDetectedTime.getTime();
var now = new Date().getTime();
var overdueTimestamp = now - lastHeartbeatTime;
var dialogTime = inactivityTimeout - countdownDialogTime;
if(dialogTime <= overdueTimestamp && inactivityTimeout >= overdueTimestamp) {
var sec = Math.round((inactivityTimeout - overdueTimestamp) / 1000);
console.log(sec);
var dialogStr = "You will be log out in "+sec+" seconds.";
if (sec === 0) {
$("#staleSessionCountdownModal").dialog('close');
} else {
if(sec === 1) {
dialogStr = "You will be log out in "+sec+" second.";
}
$('#staleSessionCountdownModal').html(dialogStr);
$("#staleSessionCountdownModal").dialog('open');
// Remove border of close button
$(".ui-button:focus").css("outline", "none");
}
} else {
$("#staleSessionCountdownModal").dialog('close');
}
}
}, 1000);
} }
// //
// detect activity and mark it as detected on any of the following events // detect activity and mark it as detected on any of the following events
// //
$(document).on(activityEvents, function(event) { $(document).on(activityEvents, function() {
activityDetected = true; activityDetected = true;
activityDetectedTime = new Date(); // Event to close dialog
$("#staleSessionCountdownModal").dialog('close'); $.event.trigger('TriggerCloseTimeoutCountdownDialog');
dialogIsOpen = false;
}); });
}); });

View File

@ -8,7 +8,6 @@ Package.describe({
Package.onUse(function(api) { Package.onUse(function(api) {
api.use('accounts-base@1.0.0', ['client','server']); api.use('accounts-base@1.0.0', ['client','server']);
api.use('jquery@1.0.0', 'client'); api.use('jquery@1.0.0', 'client');
api.use('mizzao:jquery-ui', 'client');
api.addFiles('client.js', 'client'); api.addFiles('client.js', 'client');
api.addFiles('server.js', 'server'); api.addFiles('server.js', 'server');
}); });

View File

@ -17,7 +17,9 @@ Meteor.methods({
if (!this.userId) { return; } if (!this.userId) { return; }
var user = Meteor.users.findOne(this.userId); var user = Meteor.users.findOne(this.userId);
if (user) { if (user) {
Meteor.users.update(user._id, {$set: {heartbeat: new Date()}}); var heartbeatTime = new Date();
Meteor.users.update(user._id, {$set: {heartbeat: heartbeatTime}});
return heartbeatTime;
} }
} }
}); });

View File

@ -19,9 +19,11 @@
] ]
}, },
"public": { "public": {
"staleSessionInactivityTimeout": 1800000, "staleSessionInactivityTimeout": 300000,
"staleSessionHeartbeatInterval": 180000, "staleSessionHeartbeatInterval": 30000,
"staleSessionPurgeInterval": 60000, "staleSessionPurgeInterval": 15000,
"staleSessionActivityEvents": "mousemove click keydown" "staleSessionActivityEvents": "mousemove click keydown",
"showCountdownDialog": true,
"dialogTimeout": 30000
} }
} }

View File

@ -17,9 +17,11 @@
] ]
}, },
"public": { "public": {
"staleSessionInactivityTimeout": 1800000, "staleSessionInactivityTimeout": 300000,
"staleSessionHeartbeatInterval": 180000, "staleSessionHeartbeatInterval": 30000,
"staleSessionPurgeInterval": 60000, "staleSessionPurgeInterval": 15000,
"staleSessionActivityEvents": "mousemove click keydown" "staleSessionActivityEvents": "mousemove click keydown",
"showCountdownDialog": true,
"dialogTimeout": 30000
} }
} }

View File

@ -18,9 +18,11 @@
] ]
}, },
"public": { "public": {
"staleSessionInactivityTimeout": 1800000, "staleSessionInactivityTimeout": 300000,
"staleSessionHeartbeatInterval": 180000, "staleSessionHeartbeatInterval": 30000,
"staleSessionPurgeInterval": 60000, "staleSessionPurgeInterval": 15000,
"staleSessionActivityEvents": "mousemove click keydown" "staleSessionActivityEvents": "mousemove click keydown",
"showCountdownDialog": true,
"dialogTimeout": 30000
} }
} }

View File

@ -17,9 +17,11 @@
] ]
}, },
"public": { "public": {
"staleSessionInactivityTimeout": 30000, "staleSessionInactivityTimeout": 300000,
"staleSessionHeartbeatInterval": 3000, "staleSessionHeartbeatInterval": 30000,
"staleSessionPurgeInterval": 1000, "staleSessionPurgeInterval": 15000,
"staleSessionActivityEvents": "mousemove click keydown" "staleSessionActivityEvents": "mousemove click keydown",
"showCountdownDialog": true,
"dialogTimeout": 30000
} }
} }