在 jsf web 应用程序中,基于 Javascript 的 session 计时器适用于 Chrome 但不适用于 IE
In a jsf web application, a Javascript based session timer works on Chrome but not on IE
在一个基于 Seam 和 Richfaces 的 jsf web 应用程序中,我 运行 遇到了一个关于不同浏览器的问题。代码(以及我尝试过的每个变体)在 Chrome 中都可以完美运行,但在 Internet Explorer 中却不行(我正在测试版本 11)。
代码应该开始并在 header 中显示 session-timeout 倒计时。在模板文件的开头,超时从应用程序首选项中检索并存储在隐藏字段中。每当加载新页面或触发 AJAX 请求 (resetInactivityTimer()
) 时,倒计时计时器都会重置。
我在 IE 中有 2 个问题:
看来IE上没有触发window.onload
功能。当在控制台中手动触发时,计数器开始正常工作。
手动启动计数器时,触发AJAX请求时出错
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Title</title>
<link rel="shortcut icon" type="image/x-icon" href="#{facesContext.externalContext.requestContextPath}/img/favicon.ico" />
<a:loadStyle src="/stylesheet/theme.css" />
<ui:insert name="head" />
</head>
<body>
<h:inputHidden id="originalTimeoutId" value="#{preferencesManager.getPreferenceValue(Preference.HTTP_SESSION_TIMEOUT)}"/>
<a:loadScript src="/scripts/script.js"/>
<a:region id="status_zone">
<a:status for="status_zone" forceId="false" id="ajaxStatus" onstart="resetInactivityTimer()">
<f:facet name="start">
<h:panelGroup>
<div style="position: absolute; left: 50%; top: 50%; text-align:center; width: 100%; margin-left: -50%;z-index: 10001;" >
<h:graphicImage value="/img/wait.gif"/>
</div>
<rich:spacer width="95%" height="95%" style="position: absolute; z-index: 10000; cusor: wait;" />
</h:panelGroup>
</f:facet>
</a:status>
<div class="main">
<ui:include src="/layout/header.xhtml" />
<ui:include src="/layout/menu.xhtml" />
<div style="margin-top: 10px;">
<ui:insert name="body" />
</div>
<ui:include src="/layout/footer.xhtml" />
</div>
</a:region>
<script type="text/javascript">
window.onload = initCountdown();
</script>
</body>
</html>
倒数计时器显示在 Header 文件 "header.xhtml" 的右上角,该文件已加载到模板中,因此包含在每个页面中:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<div class="header">
<s:graphicImage value="#{preferencesManager.getPreferenceByteContent(Preference.LOGO)}" styleClass="logo"/>
<h:panelGrid width="92%" columns="3" columnClasses="headerCol2,headerCol3,headerCol4">
<h:outputText styleClass="titel"
value="#{cM.getStringProp('de.gai_netconsult.kodaba.text.title')}"/>
<span class="timer">Automatischer Logout in: </span>
<h:outputText id="counter" styleClass="timer"></h:outputText>
</h:panelGrid>
</div>
时间放在id="counter"
位置。
这是 Javascript 代码:"script.js"
var hiddenField;
var timeoutInSeconds;
var originalTimeout;
var originalCounter;
var initialized = false;
function initCountdown(){
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// do stuff
startCountdown();
}
function getHiddenField() {
if (hiddenField != null) {
timeoutInSeconds = parseInt(hiddenField.value) * 60;
return timeoutInSeconds;
}
try {
hiddenField = document.getElementById('originalTimeoutId');
} catch (e) {
timeoutInSeconds = 0;
}
return timeoutInSeconds;
}
function getOriginalCounter(){
return document.getElementById('counter');
}
function resetInactivityTimer() {
if (initialized) {
console.log("resetInactivityTimer - initialized: " + initialized);
stopCountdown();
countdown(timeoutInSeconds, 'counter');
}
}
function startCountdown () {
timeoutInSeconds = getHiddenField();
if(timeoutInSeconds == 0) return;
originalCounter = getOriginalCounter();
if(timeoutInSeconds == null || originalCounter == null) {
setTimeout(function(){
startCountdown()}, 1000);
}
if(timeoutInSeconds != null && originalCounter != null){
initialized = true;
originalTimeout = timeoutInSeconds;
countdown(originalTimeout, 'counter');
}
}
function stopCountdown() {
var element = document.getElementById('counter');
clearTimeout(element.timerId);
}
function leadingzero(number) {
return (number < 10) ? '0' + number : number;
}
function countdown(seconds, target) {
var element = document.getElementById(target);
element.seconds = seconds;
calculateAndShow('counter');
}
function calculateAndShow(target) {
var element = document.getElementById('counter');
if (element.seconds >= 0) {
element.timerId = window.setTimeout(calculateAndShow,1000,target);
var h = Math.floor(element.seconds / 3600);
var m = Math.floor((element.seconds % 3600) / 60);
var s = element.seconds % 60;
element.innerHTML=
leadingzero(h) + ':' +
leadingzero(m) + ':' +
leadingzero(s);
element.seconds--;
} else {
completed(target);
return false;
}
}
function completed(target) {
var element = document.getElementById(target);
element.innerHTML = "<strong>Finished!<\/strong>";
}
我尝试的一些东西正在替换
<script type="text/javascript">
window.onload = initCountdown();
</script>
和
<script type="text/javascript">
if (window.attachEvent) {window.attachEvent('onload', initCountdown());}
else if (window.addEventListener) {window.addEventListener('load', initCountdown(), false);}
else {document.addEventListener('load', initCountdown(), false);}
</script>
这导致"Typeconflict"。
或与:
<rich:jQuery name="jcountdown" query="initCountdown()" timing="onload"/>
None 有帮助。
我最终能够让我的计时器工作,我将post我的解决方案在这里:
问题一:
<script type="text/javascript">
jQuery(document).ready(function(){
startCountdown();
});
</script>
而不是 window.onload = startCountdown();
解决了问题。
重要提示:使用任何console.log()
语句时,该函数只会在打开开发者控制台时执行! (F12).
问题二:(AJAX)
Richfaces 3.3 版与 IE8 以上的任何 Internet Explorer 版本都不兼容。
应用补丁很重要。这个site详细描述了这个过程。
我还必须对 Javascript 代码进行许多更改。我相信这可以写得更优雅,但我承认我真的 Javascript 一点也不了解......无论如何我正在 post 编写我的代码,以防有人找到它有用:
var hiddenField;
var timeoutInSeconds;
var originalTimeout;
var originalCounter;
function getHiddenField() {
if (hiddenField != null) {
timeoutInSeconds = parseInt(hiddenField.value) * 60 -1;
timeoutInSeconds;
return timeoutInSeconds;
}
try {
hiddenField = document.getElementById('originalTimeoutId');
} catch (e) {
timeoutInSeconds = 0;
}
return timeoutInSeconds;
}
function getOriginalCounter(){
return document.getElementById('counter');
}
function startCountdown () {
timeoutInSeconds = getHiddenField();
if(timeoutInSeconds == 0) return;
originalCounter = getOriginalCounter();
if(timeoutInSeconds == null || originalCounter == null) {
setTimeout(function(){
startCountdown()}, 1000);
}
if(timeoutInSeconds != null && originalCounter != null){
originalTimeout = timeoutInSeconds;
countdown(originalTimeout, 'counter');
}
}
function countdown(seconds, target) {
var element = document.getElementById(target);
element.seconds = seconds;
calculateAndShow('counter');
}
function resetCountdown(){
var element = document.getElementById('counter');
element.seconds = timeoutInSeconds;
updateDisplay(element);
}
function calculateAndShow() {
var element = document.getElementById('counter');
if (element.seconds > 0) {
element.timerId = window.setTimeout(calculateAndShow,1000,'counter');
updateDisplay(element);
element.seconds--;
} else {
completed();
return false;
}
}
function updateDisplay(element){
var h = Math.floor(element.seconds / 3600);
var m = Math.floor((element.seconds % 3600) / 60);
var s = element.seconds % 60;
element.innerHTML =
leadingzero(h) + ':' +
leadingzero(m) + ':' +
leadingzero(s);
}
function leadingzero(number) {
return (number < 10) ? '0' + number : number;
}
function completed() {
var element = document.getElementById('counter');
element.innerHTML = "<strong>Beendet!<\/strong>";
logoutCallBackToServer();
}
在您的某个 xhtml 文件(模板、页眉、菜单等)中的某处,您还需要添加以下行:
<a4j:jsFunction name="logoutCallBackToServer" immediate="true" action="#{identity.logout}" />
这将确保用户在倒计时达到零时准确注销,以防这与实际会话超时不 100% 匹配。
在一个基于 Seam 和 Richfaces 的 jsf web 应用程序中,我 运行 遇到了一个关于不同浏览器的问题。代码(以及我尝试过的每个变体)在 Chrome 中都可以完美运行,但在 Internet Explorer 中却不行(我正在测试版本 11)。
代码应该开始并在 header 中显示 session-timeout 倒计时。在模板文件的开头,超时从应用程序首选项中检索并存储在隐藏字段中。每当加载新页面或触发 AJAX 请求 (resetInactivityTimer()
) 时,倒计时计时器都会重置。
我在 IE 中有 2 个问题:
看来IE上没有触发
window.onload
功能。当在控制台中手动触发时,计数器开始正常工作。手动启动计数器时,触发AJAX请求时出错
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Title</title> <link rel="shortcut icon" type="image/x-icon" href="#{facesContext.externalContext.requestContextPath}/img/favicon.ico" /> <a:loadStyle src="/stylesheet/theme.css" /> <ui:insert name="head" /> </head> <body> <h:inputHidden id="originalTimeoutId" value="#{preferencesManager.getPreferenceValue(Preference.HTTP_SESSION_TIMEOUT)}"/> <a:loadScript src="/scripts/script.js"/> <a:region id="status_zone"> <a:status for="status_zone" forceId="false" id="ajaxStatus" onstart="resetInactivityTimer()"> <f:facet name="start"> <h:panelGroup> <div style="position: absolute; left: 50%; top: 50%; text-align:center; width: 100%; margin-left: -50%;z-index: 10001;" > <h:graphicImage value="/img/wait.gif"/> </div> <rich:spacer width="95%" height="95%" style="position: absolute; z-index: 10000; cusor: wait;" /> </h:panelGroup> </f:facet> </a:status> <div class="main"> <ui:include src="/layout/header.xhtml" /> <ui:include src="/layout/menu.xhtml" /> <div style="margin-top: 10px;"> <ui:insert name="body" /> </div> <ui:include src="/layout/footer.xhtml" /> </div> </a:region> <script type="text/javascript"> window.onload = initCountdown(); </script> </body> </html>
倒数计时器显示在 Header 文件 "header.xhtml" 的右上角,该文件已加载到模板中,因此包含在每个页面中:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html">
<div class="header">
<s:graphicImage value="#{preferencesManager.getPreferenceByteContent(Preference.LOGO)}" styleClass="logo"/>
<h:panelGrid width="92%" columns="3" columnClasses="headerCol2,headerCol3,headerCol4">
<h:outputText styleClass="titel"
value="#{cM.getStringProp('de.gai_netconsult.kodaba.text.title')}"/>
<span class="timer">Automatischer Logout in: </span>
<h:outputText id="counter" styleClass="timer"></h:outputText>
</h:panelGrid>
</div>
时间放在id="counter"
位置。
这是 Javascript 代码:"script.js"
var hiddenField;
var timeoutInSeconds;
var originalTimeout;
var originalCounter;
var initialized = false;
function initCountdown(){
// quit if this function has already been called
if (arguments.callee.done) return;
// flag this function so we don't do the same thing twice
arguments.callee.done = true;
// do stuff
startCountdown();
}
function getHiddenField() {
if (hiddenField != null) {
timeoutInSeconds = parseInt(hiddenField.value) * 60;
return timeoutInSeconds;
}
try {
hiddenField = document.getElementById('originalTimeoutId');
} catch (e) {
timeoutInSeconds = 0;
}
return timeoutInSeconds;
}
function getOriginalCounter(){
return document.getElementById('counter');
}
function resetInactivityTimer() {
if (initialized) {
console.log("resetInactivityTimer - initialized: " + initialized);
stopCountdown();
countdown(timeoutInSeconds, 'counter');
}
}
function startCountdown () {
timeoutInSeconds = getHiddenField();
if(timeoutInSeconds == 0) return;
originalCounter = getOriginalCounter();
if(timeoutInSeconds == null || originalCounter == null) {
setTimeout(function(){
startCountdown()}, 1000);
}
if(timeoutInSeconds != null && originalCounter != null){
initialized = true;
originalTimeout = timeoutInSeconds;
countdown(originalTimeout, 'counter');
}
}
function stopCountdown() {
var element = document.getElementById('counter');
clearTimeout(element.timerId);
}
function leadingzero(number) {
return (number < 10) ? '0' + number : number;
}
function countdown(seconds, target) {
var element = document.getElementById(target);
element.seconds = seconds;
calculateAndShow('counter');
}
function calculateAndShow(target) {
var element = document.getElementById('counter');
if (element.seconds >= 0) {
element.timerId = window.setTimeout(calculateAndShow,1000,target);
var h = Math.floor(element.seconds / 3600);
var m = Math.floor((element.seconds % 3600) / 60);
var s = element.seconds % 60;
element.innerHTML=
leadingzero(h) + ':' +
leadingzero(m) + ':' +
leadingzero(s);
element.seconds--;
} else {
completed(target);
return false;
}
}
function completed(target) {
var element = document.getElementById(target);
element.innerHTML = "<strong>Finished!<\/strong>";
}
我尝试的一些东西正在替换
<script type="text/javascript">
window.onload = initCountdown();
</script>
和
<script type="text/javascript">
if (window.attachEvent) {window.attachEvent('onload', initCountdown());}
else if (window.addEventListener) {window.addEventListener('load', initCountdown(), false);}
else {document.addEventListener('load', initCountdown(), false);}
</script>
这导致"Typeconflict"。
或与:
<rich:jQuery name="jcountdown" query="initCountdown()" timing="onload"/>
None 有帮助。
我最终能够让我的计时器工作,我将post我的解决方案在这里:
问题一:
<script type="text/javascript">
jQuery(document).ready(function(){
startCountdown();
});
</script>
而不是 window.onload = startCountdown();
解决了问题。
重要提示:使用任何console.log()
语句时,该函数只会在打开开发者控制台时执行! (F12).
问题二:(AJAX) Richfaces 3.3 版与 IE8 以上的任何 Internet Explorer 版本都不兼容。 应用补丁很重要。这个site详细描述了这个过程。
我还必须对 Javascript 代码进行许多更改。我相信这可以写得更优雅,但我承认我真的 Javascript 一点也不了解......无论如何我正在 post 编写我的代码,以防有人找到它有用:
var hiddenField;
var timeoutInSeconds;
var originalTimeout;
var originalCounter;
function getHiddenField() {
if (hiddenField != null) {
timeoutInSeconds = parseInt(hiddenField.value) * 60 -1;
timeoutInSeconds;
return timeoutInSeconds;
}
try {
hiddenField = document.getElementById('originalTimeoutId');
} catch (e) {
timeoutInSeconds = 0;
}
return timeoutInSeconds;
}
function getOriginalCounter(){
return document.getElementById('counter');
}
function startCountdown () {
timeoutInSeconds = getHiddenField();
if(timeoutInSeconds == 0) return;
originalCounter = getOriginalCounter();
if(timeoutInSeconds == null || originalCounter == null) {
setTimeout(function(){
startCountdown()}, 1000);
}
if(timeoutInSeconds != null && originalCounter != null){
originalTimeout = timeoutInSeconds;
countdown(originalTimeout, 'counter');
}
}
function countdown(seconds, target) {
var element = document.getElementById(target);
element.seconds = seconds;
calculateAndShow('counter');
}
function resetCountdown(){
var element = document.getElementById('counter');
element.seconds = timeoutInSeconds;
updateDisplay(element);
}
function calculateAndShow() {
var element = document.getElementById('counter');
if (element.seconds > 0) {
element.timerId = window.setTimeout(calculateAndShow,1000,'counter');
updateDisplay(element);
element.seconds--;
} else {
completed();
return false;
}
}
function updateDisplay(element){
var h = Math.floor(element.seconds / 3600);
var m = Math.floor((element.seconds % 3600) / 60);
var s = element.seconds % 60;
element.innerHTML =
leadingzero(h) + ':' +
leadingzero(m) + ':' +
leadingzero(s);
}
function leadingzero(number) {
return (number < 10) ? '0' + number : number;
}
function completed() {
var element = document.getElementById('counter');
element.innerHTML = "<strong>Beendet!<\/strong>";
logoutCallBackToServer();
}
在您的某个 xhtml 文件(模板、页眉、菜单等)中的某处,您还需要添加以下行:
<a4j:jsFunction name="logoutCallBackToServer" immediate="true" action="#{identity.logout}" />
这将确保用户在倒计时达到零时准确注销,以防这与实际会话超时不 100% 匹配。