autologout.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /**
  2. * @file
  3. * JavaScript for autologout.
  4. */
  5. (function ($, Drupal) {
  6. 'use strict';
  7. /**
  8. * Attaches the batch behavior for autologout.
  9. *
  10. * @type {Drupal~behavior}
  11. */
  12. Drupal.behaviors.autologout = {
  13. attach: function (context, settings) {
  14. if (context !== document) {
  15. return;
  16. }
  17. var paddingTimer;
  18. var theDialog;
  19. var t;
  20. var localSettings;
  21. // Activity is a boolean used to detect a user has
  22. // interacted with the page.
  23. var activity;
  24. // Timer to keep track of activity resets.
  25. var activityResetTimer;
  26. // Prevent settings being overridden by ajax callbacks by cloning it.
  27. localSettings = jQuery.extend(true, {}, settings.autologout);
  28. // Add timer element to prevent detach of all behaviours.
  29. var timerMarkup = $('<div id="timer"></div>').hide();
  30. $('body').append(timerMarkup);
  31. if (localSettings.refresh_only) {
  32. // On pages where user shouldn't be logged out, don't set the timer.
  33. t = setTimeout(keepAlive, localSettings.timeout);
  34. }
  35. else {
  36. // Set no activity to start with.
  37. activity = false;
  38. // Bind formUpdated events to preventAutoLogout event.
  39. $('body').bind('formUpdated', function (event) {
  40. $(event.target).trigger('preventAutologout');
  41. });
  42. // Bind formUpdated events to preventAutoLogout event.
  43. $('body').bind('mousemove', function (event) {
  44. $(event.target).trigger('preventAutologout');
  45. });
  46. // Support for CKEditor.
  47. if (typeof CKEDITOR !== 'undefined') {
  48. CKEDITOR.on('instanceCreated', function (e) {
  49. e.editor.on('contentDom', function () {
  50. e.editor.document.on('keyup', function (event) {
  51. // Keyup event in ckeditor should prevent autologout.
  52. $(e.editor.element.$).trigger('preventAutologout');
  53. });
  54. });
  55. });
  56. }
  57. $('body').bind('preventAutologout', function (event) {
  58. // When the preventAutologout event fires, we set activity to true.
  59. activity = true;
  60. // Clear timer if one exists.
  61. clearTimeout(activityResetTimer);
  62. // Set a timer that goes off and resets this activity indicator after
  63. // a minute, otherwise sessions never timeout.
  64. activityResetTimer = setTimeout(function () {
  65. activity = false;
  66. }, 60000);
  67. });
  68. // On pages where the user should be logged out, set the timer to popup
  69. // and log them out.
  70. t = setTimeout(init, localSettings.timeout);
  71. }
  72. function init() {
  73. var noDialog = settings.autologout.no_dialog;
  74. if (activity) {
  75. // The user has been active on the page.
  76. activity = false;
  77. refresh();
  78. }
  79. else {
  80. // The user has not been active, ask them if they want to stay logged
  81. // in and start the logout timer.
  82. paddingTimer = setTimeout(confirmLogout, localSettings.timeout_padding);
  83. // While the countdown timer is going, lookup the remaining time. If
  84. // there is more time remaining (i.e. a user is navigating in another
  85. // tab), then reset the timer for opening the dialog.
  86. Drupal.Ajax['autologout.getTimeLeft'].autologoutGetTimeLeft(function (time) {
  87. if (time > 0) {
  88. clearTimeout(paddingTimer);
  89. t = setTimeout(init, time);
  90. }
  91. else {
  92. // Logout user right away without displaying a confirmation dialog.
  93. if (noDialog) {
  94. logout();
  95. return;
  96. }
  97. theDialog = dialog();
  98. }
  99. });
  100. }
  101. }
  102. function dialog() {
  103. var buttons = {};
  104. buttons[Drupal.t('Yes')] = function () {
  105. $(this).dialog("destroy");
  106. clearTimeout(paddingTimer);
  107. refresh();
  108. };
  109. buttons[Drupal.t('No')] = function () {
  110. $(this).dialog("destroy");
  111. logout();
  112. };
  113. return $('<div id="autologout-confirm">' + localSettings.message + '</div>').dialog({
  114. modal: true,
  115. closeOnEscape: false,
  116. width: "auto",
  117. dialogClass: 'autologout-dialog',
  118. title: localSettings.title,
  119. buttons: buttons,
  120. close: function (event, ui) {
  121. logout();
  122. }
  123. });
  124. }
  125. // A user could have used the reset button on the tab/window they're
  126. // actively using, so we need to double check before actually logging out.
  127. function confirmLogout() {
  128. $(theDialog).dialog('destroy');
  129. Drupal.Ajax['autologout.getTimeLeft'].autologoutGetTimeLeft(function (time) {
  130. if (time > 0) {
  131. t = setTimeout(init, time);
  132. }
  133. else {
  134. logout();
  135. }
  136. });
  137. }
  138. function logout() {
  139. if (localSettings.use_alt_logout_method) {
  140. window.location = drupalSettings.path.baseUrl + "autologout_ahah_logout";
  141. }
  142. else {
  143. $.ajax({
  144. url: drupalSettings.path.baseUrl + "autologout_ahah_logout",
  145. type: "POST",
  146. beforeSend: function (xhr) {
  147. xhr.setRequestHeader('X-Requested-With', {
  148. toString: function (){
  149. return '';
  150. }
  151. });
  152. },
  153. success: function () {
  154. window.location = localSettings.redirect_url;
  155. },
  156. error: function (XMLHttpRequest, textStatus) {
  157. if (XMLHttpRequest.status === 403 || XMLHttpRequest.status === 404) {
  158. window.location = localSettings.redirect_url;
  159. }
  160. }
  161. });
  162. }
  163. }
  164. /**
  165. * Get the remaining time.
  166. *
  167. * Use the Drupal ajax library to handle get time remaining events
  168. * because if using the JS Timer, the return will update it.
  169. *
  170. * @param function callback(time)
  171. * The function to run when ajax is successful. The time parameter
  172. * is the time remaining for the current user in ms.
  173. */
  174. Drupal.Ajax.prototype.autologoutGetTimeLeft = function (callback) {
  175. var ajax = this;
  176. if (ajax.ajaxing) {
  177. return false;
  178. }
  179. ajax.options.success = function (response, status) {
  180. if (typeof response == 'string') {
  181. response = $.parseJSON(response);
  182. }
  183. if (typeof response[0].command === 'string' && response[0].command === 'alert') {
  184. // In the event of an error, we can assume user has been logged out.
  185. window.location = localSettings.redirect_url;
  186. }
  187. callback(response[1].settings.time);
  188. response[0].data = '<div id="timer" style="display: none;">' + response[0].data + '</div>';
  189. // Let Drupal.ajax handle the JSON response.
  190. return ajax.success(response, status);
  191. };
  192. try {
  193. $.ajax(ajax.options);
  194. }
  195. catch (e) {
  196. ajax.ajaxing = false;
  197. }
  198. };
  199. Drupal.Ajax['autologout.getTimeLeft'] = Drupal.ajax({
  200. base: null,
  201. element: document.body,
  202. url: drupalSettings.path.baseUrl + 'autologout_ajax_get_time_left',
  203. event: 'autologout.getTimeLeft',
  204. error: function (XMLHttpRequest, textStatus) {
  205. // Disable error reporting to the screen.
  206. }
  207. });
  208. /**
  209. * Handle refresh event.
  210. *
  211. * Use the Drupal ajax library to handle refresh events because if using
  212. * the JS Timer, the return will update it.
  213. *
  214. * @param function timerFunction
  215. * The function to tell the timer to run after its been restarted.
  216. */
  217. Drupal.Ajax.prototype.autologoutRefresh = function (timerfunction) {
  218. var ajax = this;
  219. if (ajax.ajaxing) {
  220. return false;
  221. }
  222. ajax.options.success = function (response, status) {
  223. if (typeof response === 'string') {
  224. response = $.parseJSON(response);
  225. }
  226. if (typeof response[0].command === 'string' && response[0].command === 'alert') {
  227. // In the event of an error, we can assume the user has been logged out.
  228. window.location = localSettings.redirect_url;
  229. }
  230. t = setTimeout(timerfunction, localSettings.timeout);
  231. activity = false;
  232. // Wrap response data in timer markup to prevent detach of all behaviors.
  233. response[0].data = '<div id="timer" style="display: none;">' + response[0].data + '</div>';
  234. // Let Drupal.ajax handle the JSON response.
  235. return ajax.success(response, status);
  236. };
  237. try {
  238. $.ajax(ajax.options);
  239. }
  240. catch (e) {
  241. ajax.ajaxing = false;
  242. }
  243. };
  244. Drupal.Ajax['autologout.refresh'] = Drupal.ajax({
  245. base: null,
  246. element: document.body,
  247. url: drupalSettings.path.baseUrl + 'autologout_ahah_set_last',
  248. event: 'autologout.refresh',
  249. error: function (XMLHttpRequest, textStatus) {
  250. // Disable error reporting to the screen.
  251. }
  252. });
  253. function keepAlive() {
  254. Drupal.Ajax['autologout.refresh'].autologoutRefresh(keepAlive);
  255. }
  256. function refresh() {
  257. Drupal.Ajax['autologout.refresh'].autologoutRefresh(init);
  258. }
  259. // Check if the page was loaded via a back button click.
  260. var $dirty_bit = $('#autologout-cache-check-bit');
  261. if ($dirty_bit.length !== 0) {
  262. if ($dirty_bit.val() === '1') {
  263. // Page was loaded via back button click, we should refresh the timer.
  264. refresh();
  265. }
  266. $dirty_bit.val('1');
  267. }
  268. }
  269. };
  270. })(jQuery, Drupal);