2 * This file is part of the TYPO3 CMS project.
4 * It is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License, either version 2
6 * of the License, or any later version.
8 * For the full copyright and license information, please read the
9 * LICENSE.txt file that was distributed with this source code.
11 * The TYPO3 project - inspiring people to share!
15 * Module: TYPO3/CMS/Backend/LoginRefresh
16 * Task that periodically checks if a blocking event in the backend occurred and
17 * displays a proper dialog to the user.
19 define(['jquery', 'TYPO3/CMS/Backend/Notification', 'TYPO3/CMS/Rsaauth/RsaEncryptionModule', 'bootstrap'], function($, Typo3Notification
, RsaEncryption
) {
24 * @type {{identifier: {loginrefresh: string, lockedModal: string, loginFormModal: string}, options: {modalConfig: {backdrop: string}}, webNotification: null, intervalTime: integer, intervalId: null, backendIsLocked: boolean, isTimingOut: boolean, $timeoutModal: string, $backendLockedModal: string, $loginForm: string, loginFramesetUrl: string, logoutUrl: string}}
25 * @exports TYPO3/CMS/Backend/LoginRefresh
29 loginrefresh
: 't3-modal-loginrefresh',
30 lockedModal
: 't3-modal-backendlocked',
31 loginFormModal
: 't3-modal-backendloginform'
38 webNotification
: null,
41 backendIsLocked
: false,
44 $backendLockedModal
: '',
51 * Starts the session check task (if not running already)
53 LoginRefresh
.startTask = function() {
54 if (LoginRefresh
.intervalId
!== null) {
58 // set interval to 60 seconds
59 var interval
= 1000 * LoginRefresh
.intervalTime
;
60 LoginRefresh
.intervalId
= setInterval(LoginRefresh
.checkActiveSession
, interval
);
64 * Stops the session check task
66 LoginRefresh
.stopTask = function() {
67 clearInterval(LoginRefresh
.intervalId
);
68 LoginRefresh
.intervalId
= null;
72 * Generates a modal dialog as template.
74 * @param {String} identifier
77 LoginRefresh
.generateModal = function(identifier
) {
78 return TYPO3
.jQuery('<div />', {id
: identifier
, class: 't3-modal t3-blr-modal ' + identifier
+ ' modal fade'}).append(
79 $('<div />', {class: 'modal-dialog'}).append(
80 $('<div />', {class: 'modal-content'}).append(
81 $('<div />', {class: 'modal-header'}).append(
82 $('<h4 />', {class: 'modal-title'})
84 $('<div />', {class: 'modal-body'}),
85 $('<div />', {class: 'modal-footer'})
94 * @param {integer} intervalTime
96 LoginRefresh
.setIntervalTime = function(intervalTime
) {
97 // To avoid the integer overflow in setInterval, we limit the interval time to be one request per day
98 LoginRefresh
.intervalTime
= Math
.min(intervalTime
, 86400);
104 * @param {String} logoutUrl
106 LoginRefresh
.setLogoutUrl = function(logoutUrl
) {
107 LoginRefresh
.logoutUrl
= logoutUrl
;
111 * Generates the modal displayed on near session time outs
113 LoginRefresh
.initializeTimeoutModal = function() {
114 LoginRefresh
.$timeoutModal
= LoginRefresh
.generateModal(LoginRefresh
.identifier
.loginrefresh
);
115 LoginRefresh
.$timeoutModal
.addClass('t3-modal-notice');
116 LoginRefresh
.$timeoutModal
.find('.modal-header h4').text(TYPO3
.LLL
.core
.login_about_to_expire_title
);
117 LoginRefresh
.$timeoutModal
.find('.modal-body').append(
118 $('<p />').text(TYPO3
.LLL
.core
.login_about_to_expire
),
119 $('<div />', {class: 'progress'}).append(
121 class: 'progress-bar progress-bar-warning progress-bar-striped active',
123 'aria-valuemin': '0',
124 'aria-valuemax': '100'
126 $('<span />', {class: 'sr-only'})
130 LoginRefresh
.$timeoutModal
.find('.modal-footer').append(
131 $('<button />', {class: 'btn btn-default', 'data-action': 'logout'}).text(TYPO3
.LLL
.core
.refresh_login_logout_button
).on('click', function() {
132 top
.location
.href
= LoginRefresh
.logoutUrl
;
134 $('<button />', {class: 'btn btn-primary t3js-active', 'data-action': 'refreshSession'}).text(TYPO3
.LLL
.core
.refresh_login_refresh_button
).on('click', function() {
136 url
: TYPO3
.settings
.ajaxUrls
['login_timedout'],
138 success: function() {
139 LoginRefresh
.hideTimeoutModal();
144 LoginRefresh
.registerDefaultModalEvents(LoginRefresh
.$timeoutModal
);
146 $('body').append(LoginRefresh
.$timeoutModal
);
150 * Shows the timeout dialog. If the backend is not focused, a Web Notification
153 LoginRefresh
.showTimeoutModal = function() {
154 LoginRefresh
.isTimingOut
= true;
155 LoginRefresh
.$timeoutModal
.modal(LoginRefresh
.options
.modalConfig
);
156 LoginRefresh
.fillProgressbar(LoginRefresh
.$timeoutModal
);
158 if (typeof Notification
!== 'undefined' && Notification
.permission
=== 'granted' && !LoginRefresh
.isPageActive()) {
159 LoginRefresh
.webNotification
= new Notification(TYPO3
.LLL
.core
.login_about_to_expire_title
, {
160 body
: TYPO3
.LLL
.core
.login_about_to_expire
,
161 icon
: '/typo3/sysext/backend/Resources/Public/Images/Logo.png'
163 LoginRefresh
.webNotification
.onclick = function() {
170 * Hides the timeout dialog. If a Web Notification is displayed, close it too.
172 LoginRefresh
.hideTimeoutModal = function() {
173 LoginRefresh
.isTimingOut
= false;
174 LoginRefresh
.$timeoutModal
.modal('hide');
176 if (typeof Notification
!== 'undefined' && LoginRefresh
.webNotification
!== null) {
177 LoginRefresh
.webNotification
.close();
182 * Generates the modal displayed if the backend is locked.
184 LoginRefresh
.initializeBackendLockedModal = function() {
185 LoginRefresh
.$backendLockedModal
= LoginRefresh
.generateModal(LoginRefresh
.identifier
.lockedModal
);
186 LoginRefresh
.$backendLockedModal
.find('.modal-header h4').text(TYPO3
.LLL
.core
.please_wait
);
187 LoginRefresh
.$backendLockedModal
.find('.modal-body').append(
188 $('<p />').text(TYPO3
.LLL
.core
.be_locked
)
190 LoginRefresh
.$backendLockedModal
.find('.modal-footer').remove();
192 $('body').append(LoginRefresh
.$backendLockedModal
);
196 * Shows the "backend locked" dialog.
198 LoginRefresh
.showBackendLockedModal = function() {
199 LoginRefresh
.$backendLockedModal
.modal(LoginRefresh
.options
.modalConfig
);
203 * Hides the "backend locked" dialog.
205 LoginRefresh
.hideBackendLockedModal = function() {
206 LoginRefresh
.$backendLockedModal
.modal('hide');
210 * Generates the login form displayed if the session has timed out.
212 LoginRefresh
.initializeLoginForm = function() {
213 if (TYPO3
.configuration
.showRefreshLoginPopup
) {
214 // dialog is not required if "showRefreshLoginPopup" is enabled
218 LoginRefresh
.$loginForm
= LoginRefresh
.generateModal(LoginRefresh
.identifier
.loginFormModal
);
219 LoginRefresh
.$loginForm
.addClass('t3-modal-notice');
220 var refresh_login_title
= String(TYPO3
.LLL
.core
.refresh_login_title
).replace('%s', TYPO3
.configuration
.username
);
221 LoginRefresh
.$loginForm
.find('.modal-header h4').text(refresh_login_title
);
222 LoginRefresh
.$loginForm
.find('.modal-body').append(
223 $('<p />').text(TYPO3
.LLL
.core
.login_expired
),
224 $('<form />', {id
: 'beLoginRefresh', method
: 'POST', action
: TYPO3
.settings
.ajaxUrls
['login']}).append(
225 $('<div />', {class: 'form-group'}).append(
226 $('<input />', {type
: 'password', name
: 'p_field', autofocus
: 'autofocus', class: 'form-control', placeholder
: TYPO3
.LLL
.core
.refresh_login_password
, 'data-rsa-encryption': 't3-loginrefres-userident'})
228 $('<input />', {type
: 'hidden', name
: 'username', value
: TYPO3
.configuration
.username
}),
229 $('<input />', {type
: 'hidden', name
: 'userident', id
: 't3-loginrefres-userident'})
232 LoginRefresh
.$loginForm
.find('.modal-footer').append(
233 $('<a />', {href
: LoginRefresh
.logoutUrl
, class: 'btn btn-default'}).text(TYPO3
.LLL
.core
.refresh_exit_button
),
234 $('<button />', {type
: 'button', class: 'btn btn-primary', 'data-action': 'refreshSession'})
235 .text(TYPO3
.LLL
.core
.refresh_login_button
)
236 .on('click', function(e
) {
237 LoginRefresh
.$loginForm
.find('form').submit();
240 var $LoginRefreshForm
= LoginRefresh
.$loginForm
.find('#beLoginRefresh');
241 if (undefined !== RsaEncryption
) {
242 RsaEncryption
.registerForm($LoginRefreshForm
.get(0));
244 LoginRefresh
.registerDefaultModalEvents($LoginRefreshForm
).on('submit', LoginRefresh
.submitForm
);
246 $('body').append(LoginRefresh
.$loginForm
);
250 * Shows the login form.
252 LoginRefresh
.showLoginForm = function() {
255 url
: TYPO3
.settings
.ajaxUrls
['logout'],
257 success: function() {
258 if (TYPO3
.configuration
.showRefreshLoginPopup
) {
259 LoginRefresh
.showLoginPopup();
261 LoginRefresh
.$loginForm
.modal(LoginRefresh
.options
.modalConfig
);
264 failure: function() {
265 alert('something went wrong');
271 * Set login frameset url
273 LoginRefresh
.setLoginFramesetUrl = function(loginFramesetUrl
) {
274 LoginRefresh
.loginFramesetUrl
= loginFramesetUrl
;
278 * Opens the login form in a new window.
280 LoginRefresh
.showLoginPopup = function() {
281 var vHWin
= window
.open(LoginRefresh
.loginFramesetUrl
, 'relogin_' + TYPO3
.configuration
.uniqueID
, 'height=450,width=700,status=0,menubar=0,location=1');
288 * Hides the login form.
290 LoginRefresh
.hideLoginForm = function() {
291 LoginRefresh
.$loginForm
.modal('hide');
295 * Fills the progressbar attached to the given modal.
297 LoginRefresh
.fillProgressbar = function($activeModal
) {
298 if (!LoginRefresh
.isTimingOut
) {
304 $progressBar
= $activeModal
.find('.progress-bar'),
305 $srText
= $progressBar
.children('.sr-only');
307 var progress
= setInterval(function() {
308 var isOverdue
= (current
>= max
);
310 if (!LoginRefresh
.isTimingOut
|| isOverdue
) {
311 clearInterval(progress
);
315 LoginRefresh
.hideTimeoutModal();
316 LoginRefresh
.showLoginForm();
325 var percentText
= (current
) + '%';
326 $progressBar
.css('width', percentText
);
327 $srText
.text(percentText
);
332 * Creates additional data based on the security level and "submits" the form
333 * via an AJAX request.
335 * @param {Event} event
337 LoginRefresh
.submitForm = function(event
) {
338 event
.preventDefault();
340 var $form
= LoginRefresh
.$loginForm
.find('form'),
341 $passwordField
= $form
.find('input[name=p_field]'),
342 $useridentField
= $form
.find('input[name=userident]'),
343 passwordFieldValue
= $passwordField
.val();
345 if (passwordFieldValue
=== '' && $useridentField
.val() === '') {
346 Typo3Notification
.error(TYPO3
.LLL
.core
.refresh_login_failed
, TYPO3
.LLL
.core
.refresh_login_emptyPassword
);
347 $passwordField
.focus();
351 if (passwordFieldValue
) {
352 $useridentField
.val(passwordFieldValue
);
353 $passwordField
.val('');
357 login_status
: 'login'
359 $.each($form
.serializeArray(), function(i
, field
) {
360 postData
[field
.name
] = field
.value
;
363 url
: $form
.attr('action'),
366 success: function(response
) {
367 var result
= response
.login
;
368 if (result
.success
) {
370 LoginRefresh
.hideLoginForm();
372 Typo3Notification
.error(TYPO3
.LLL
.core
.refresh_login_failed
, TYPO3
.LLL
.core
.refresh_login_failed_message
);
373 $passwordField
.focus();
380 * Registers the (shown|hidden).bs.modal events.
381 * If a modal is shown, the interval check is stopped. If the modal hides,
382 * the interval check starts again.
383 * This method is not invoked for the backend locked modal, because we still
384 * need to check if the backend gets unlocked again.
386 * @param {Object} $modal
389 LoginRefresh
.registerDefaultModalEvents = function($modal
) {
390 $modal
.on('hidden.bs.modal', function() {
391 LoginRefresh
.startTask();
392 }).on('shown.bs.modal', function() {
393 LoginRefresh
.stopTask();
394 // focus the button which was configured as active button
395 LoginRefresh
.$timeoutModal
.find('.modal-footer .t3js-active').first().focus();
402 * Checks if the user is in focus of the backend.
403 * Thanks to http://stackoverflow.com/a/19519701
405 LoginRefresh
.isPageActive = function() {
406 var stateKey
, eventKey
, keys
= {
407 hidden
: 'visibilitychange',
408 webkitHidden
: 'webkitvisibilitychange',
409 mozHidden
: 'mozvisibilitychange',
410 msHidden
: 'msvisibilitychange'
413 for (stateKey
in keys
) {
414 if (stateKey
in document
) {
415 eventKey
= keys
[stateKey
];
421 document
.addEventListener(eventKey
, c
);
423 return !document
[stateKey
];
428 * Periodically called task that checks if
430 * - the user's backend session is about to expire
431 * - the user's backend session has expired
432 * - the backend got locked
434 * and opens a dialog.
436 LoginRefresh
.checkActiveSession = function() {
438 url
: TYPO3
.settings
.ajaxUrls
['login_timedout'],
442 success: function(response
) {
443 if (response
.login
.locked
) {
444 if (!LoginRefresh
.backendIsLocked
) {
445 LoginRefresh
.backendIsLocked
= true;
446 LoginRefresh
.showBackendLockedModal();
449 if (LoginRefresh
.backendIsLocked
) {
450 LoginRefresh
.backendIsLocked
= false;
451 LoginRefresh
.hideBackendLockedModal();
455 if (!LoginRefresh
.backendIsLocked
) {
456 if (response
.login
.timed_out
|| response
.login
.will_time_out
) {
457 if (response
.login
.timed_out
) {
458 LoginRefresh
.showLoginForm();
460 LoginRefresh
.showTimeoutModal();
468 LoginRefresh
.initialize = function() {
469 LoginRefresh
.initializeTimeoutModal();
470 LoginRefresh
.initializeBackendLockedModal();
471 LoginRefresh
.initializeLoginForm();
473 LoginRefresh
.startTask();
475 if (typeof Notification
!== 'undefined' && Notification
.permission
!== 'granted') {
476 Notification
.requestPermission();
481 TYPO3
.LoginRefresh
= LoginRefresh
;