Session Timed Out Patches

Solved:

  1. warning and manual save if server is unavailable
  2. AJAX heartbeat if server is available
  3. warning and manual save user when the user has logged out [403]
  4. \n versus <br> issue for message set 
  5. add heartbeat support also for comments

TODO:

  1. local save via HTML5 with version conflict prevention
  2. add Heartbeat Control
    • enable / disable heartbeat
    • locations (edit and comment handler)
    • frequency (default: 1440, 24 minutes)
  3. if server is unavailable icon for error message won't load if not already cached
  4. user POST if server is unavailable -> check server status to prevent data loss
  5. alert(div.innerHTML) versus prepend(div)
  6. localize: "This page is asking you to confirm that you want to leave – data you have entered may not be saved." defunct
    • Browsers removed custom messages in onbeforeunload dialogs to prevent scamming [chrome]
  7. Replace inline JavaScript
    • e.g. var itemID = document.body.getAttribute("data-foo”);
  8. build in JS debug session time counter
  9. Unsability improvements, search for good examples
  10. add Heartbeat feature to documentation

remarks:

  • currently it is sufficient to load the JS lang file only with WikiEdit




commit:a5fbdf565b7b11de630b3fafd1c8adbdabec20fd
commit:c9a74a4f5c7bf13046bcaaad7f5236f4010f30e1

diff --git a/wacko/handler/page/_autocomplete.php b/wacko/handler/page/_autocomplete.php
index 5692448..3e1ba47 100644
--- a/wacko/handler/page/_autocomplete.php
+++ b/wacko/handler/page/_autocomplete.php
@@ -61,9 +61,18 @@
 
 // Getting a query
 _parse_query_string();
-$q        = $_GET['q'];
-$ta_id    = $_GET['ta_id'];
-
+if(isset($_GET['q']) && isset($_GET['q']))
+{
+    // Working for autocomplete
+    $q        = $_GET['q'];
+    $ta_id    = $_GET['ta_id'];
+}
+else
+{
+    // Any answer to restart session counter
+    echo '1';
+    die();
+}
 
 // 1. unwrap
 $q = utf8_ltrim($q, '/');
diff --git a/wacko/handler/page/_comments.php b/wacko/handler/page/_comments.php
index 33d079b..e06fe9c 100644
--- a/wacko/handler/page/_comments.php
+++ b/wacko/handler/page/_comments.php
@@ -266,6 +266,9 @@
                 {
                     $tpl->autocomplete = true;
                 }
+
+                // session heartbeat timeout = wiki session timeout - 40 second
+                $tpl->user_heartbeat = $this->sess->cf_gc_maxlifetime - 40;
             }
 
             $tpl->wikiedit = $this->db->base_url . Ut::join_path(IMAGE_DIR, 'wikiedit') . '/';
diff --git a/wacko/handler/page/edit.php b/wacko/handler/page/edit.php
index d82d572..6e7c9bf 100644
--- a/wacko/handler/page/edit.php
+++ b/wacko/handler/page/edit.php
@@ -11,13 +11,6 @@
 $reviewed        = 0;
 $title            = '';
 
-// invoke autocomplete if needed
-if ((isset($_GET['_autocomplete'])) && $_GET['_autocomplete'])
-{
-    include dirname(__FILE__) . '/_autocomplete.php';
-    return;
-}
-
 if ($this->has_access('read')
     && (($this->page && $this->has_access('write'))
     #        || $this->is_admin() // XXX: Only for testing - comment out afterwards!
@@ -34,6 +27,13 @@
         $this->http->redirect($this->href('new', $this->db->root_page));
     }
 
+    // invoke autocomplete if needed
+    if ((isset($_GET['_autocomplete'])) && $_GET['_autocomplete'])
+    {
+        include dirname(__FILE__) . '/_autocomplete.php';
+        return;
+    }
+
     $user    = $this->get_user();
 
     // is comment?
@@ -390,6 +390,9 @@
         {
             $tpl->autocomplete = true;
         }
+
+        // session heartbeat timeout = wiki session timeout - 40 second to let the request heartbeat and response go without fuss
+        $tpl->user_heartbeat = $this->sess->cf_gc_maxlifetime - 40;
     }
 
     $tpl->wikiedit = $this->db->base_url . Ut::join_path(IMAGE_DIR, 'wikiedit') . '/';
diff --git a/wacko/handler/page/template/_comments.tpl b/wacko/handler/page/template/_comments.tpl
index 7fdf040..1d2f1a2 100644
--- a/wacko/handler/page/template/_comments.tpl
+++ b/wacko/handler/page/template/_comments.tpl
@@ -92,9 +92,15 @@
                                     if (AutoComplete) { wEaC = new AutoComplete( wE, "[ ' href: show ' ]" ); }
                                 =]
                             wE.init('addcomment','WikiEdit','edname-w','[ ' wikiedit ' ]');
+                [= user _ =
+                            window.onload = function () {
+                                var timeout = [ ' heartbeat ' ];
+                                var name = 'add_comment';
+                                userSessionHeartbeat(timeout, name);
+                            };
+                =]
                         </script>
-                        <input type="submit" name="save" value="[ ' _t: AddCommentButton ' ]" accesskey="s">
-                        <input type="submit" name="preview" value="[ ' _t: EditPreviewButton ' ]">
+                        <input type="submit" class="btn-ok" name="save" value="[ ' _t: AddCommentButton ' ]" accesskey="s">
+                        <input type="submit" class="btn-ok" name="preview" value="[ ' _t: EditPreviewButton ' ]">
                     </form>
                 </div>
             =]
diff --git a/wacko/handler/page/template/edit.tpl b/wacko/handler/page/template/edit.tpl
index e8bf2c5..9ade2f8 100644
--- a/wacko/handler/page/template/edit.tpl
+++ b/wacko/handler/page/template/edit.tpl
@@ -79,6 +79,12 @@
                             if (AutoComplete) { wEaC = new AutoComplete( wE, "[ ' href: edit ' ]" ); }
                         =]
                     wE.init('postText','WikiEdit','edname-w','[ ' wikiedit ' ]');
+                [= user _ =
+                    window.onload = function () {
+                        var timeout = [ ' heartbeat ' ];
+                        var name = 'edit_page';
+                        userSessionHeartbeat(timeout, name);
+                    };
+                 =]
                 </script>
                 <br>
                 [ '' buttons '' ]
diff --git a/wacko/js/default.js b/wacko/js/default.js
index 004ffcb..71055c4 100644
--- a/wacko/js/default.js
+++ b/wacko/js/default.js
@@ -121,7 +121,7 @@
 // slightly modified by Kukutz
 var root = window.addEventListener || window.attachEvent ? window : document.addEventListener ? document : null;
 var cf_modified = false;
-var WIN_CLOSE_MSG = '\n' + lang.NotSavedWarning + '\n';
+//var WIN_CLOSE_MSG = '\n' + lang.NotSavedWarning + '\n';
 
 function set_modified(e, strict_e)
 {
@@ -137,7 +137,7 @@
     if (el != null)
     {
         el.style.borderColor    = '#eecc99';
-        el.title                = '[' + lang.ModifiedHint + ']';
+        el.title                = lang.ModifiedHint;
     }
 
     cf_modified = true;
@@ -155,7 +155,7 @@
 {
     if (cf_modified)
     {
-        return WIN_CLOSE_MSG;
+        return '\n' + lang.NotSavedWarning + '\n'; // WIN_CLOSE_MSG
     }
 }
 
@@ -218,3 +218,43 @@
     if (root.addEventListener) root.addEventListener('load', crit_init, false);
     else if (root.attachEvent) root.attachEvent('onload', crit_init);
 }
+
+function userSessionHeartbeat(duration, name) {
+    var sessioncounter = setInterval(function () {
+
+        // 1. Prepare new XMLHttpRequest
+        var xhr = new XMLHttpRequest();
+        var url = window.location.href + '?_autocomplete=1&rnd=' + Math.random();
+
+        xhr.onreadystatechange = function() {
+            if (xhr.readyState == 4 && xhr.status != 200) {
+                // Error handling
+                //alert(xhr.status + ': ' + (xhr.statusText ? xhr.statusText : 'Unknown')); // E.g.: 404: Not Found
+                var div = document.createElement('div');
+                div.className = 'msg error';
+                div.innerHTML = lang.SessionExpiredEditor.replace(new RegExp('\n', 'g'), '<br>');
+                alert(lang.SessionExpiredEditor);
+                document.getElementsByName(name)['0'].prepend(div);
+                var list = document.getElementsByClassName('btn-ok');
+                for (var i = 0; i < list.length; i++) {
+                    list[i].disabled = true;
+                }
+                var list = document.getElementsByClassName('btn-cancel');
+                for (var i = 0; i < list.length; i++) {
+                    list[i].disabled = true;
+                }
+                clearInterval(sessioncounter);
+            }
+
+            if (xhr.status == 200) {
+                // Response handling
+                //alert( xhr.responseText ); // responseText output
+            }
+        };
+        // 2. Configure: GET-request to url in async mode
+        xhr.open('GET', url, true);
+        // 3. Send heartbeat request
+        xhr.send();
+
+    }, duration * 1000);
+}
diff --git a/wacko/js/lang/wikiedit.bg.js b/wacko/js/lang/wikiedit.bg.js
index a7a9fe3..f71d64f 100644
--- a/wacko/js/lang/wikiedit.bg.js
+++ b/wacko/js/lang/wikiedit.bg.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Сесията ви е изтекла!\nВие сте излезли поради продължително бездействие.\n1. Запишете редакциите на формуляра си в текстов файл, за да предотвратите загуба.\n2. Обновете страницата.\n3. Влезте отново и отново изпратете.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.da.js b/wacko/js/lang/wikiedit.da.js
index 3856890..80df630 100644
--- a/wacko/js/lang/wikiedit.da.js
+++ b/wacko/js/lang/wikiedit.da.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Din session er udløbet!\nDu er logget af på grund af lang inaktivitet.\n1. Gem dine formændringer i tekstfilen for at forhindre tab.\n2. Opdater siden.\n3. Log ind igen og indsend igen.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.de.js b/wacko/js/lang/wikiedit.de.js
index be53f9b..88fddc8 100644
--- a/wacko/js/lang/wikiedit.de.js
+++ b/wacko/js/lang/wikiedit.de.js
@@ -3,6 +3,7 @@
     ReallySave :            "Wirklich speichern?",
     ModifiedHint :            "Feld wurde geändert, vergiss nicht, die Änderungen zu speichern.",
     NotSavedWarning :        "Die Änderungen wurde nicht gespeichert. Bist du sicher, dass du die Seite verlassen willst?",
+    SessionExpiredEditor :    "Deine Sitzung ist abgelaufen!\nAufgrund langer Inaktivität wurdest du abgemeldet.\n1. Speichere die eingegebenen Daten in einer Textdatei, um sie nicht zu verlieren.\n2. Lade die Seite neu.\n3. Melde dich wieder an und sende die Daten erneut.",
 
     // wikiedit.js
     HelpAbout :                "Hilfe & Über",
diff --git a/wacko/js/lang/wikiedit.el.js b/wacko/js/lang/wikiedit.el.js
index 80631fc..c68f770 100644
--- a/wacko/js/lang/wikiedit.el.js
+++ b/wacko/js/lang/wikiedit.el.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Η συνεδρία σας έχει λήξει!\nΈχετε αποσυνδεθεί λόγω μακράς αδράνειας.\n1. Αποθηκεύστε τις τροποποιήσεις της φόρμας σε αρχείο κειμένου για να αποφύγετε την απώλεια.\n2. Ανανέωσε τη σελίδα.\n3. Συνδεθείτε ξανά και υποβάλετε ξανά.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.en.js b/wacko/js/lang/wikiedit.en.js
index a7a9fe3..4cfa9a3 100644
--- a/wacko/js/lang/wikiedit.en.js
+++ b/wacko/js/lang/wikiedit.en.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Your session has expired!\nYou\'ve been logged off due to long inactivity.\n1. Save your form edits to text file to prevent loss.\n2. Refresh the page.\n3. Log in again and re-submit.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.es.js b/wacko/js/lang/wikiedit.es.js
index c0088f6..a2c21b4 100644
--- a/wacko/js/lang/wikiedit.es.js
+++ b/wacko/js/lang/wikiedit.es.js
@@ -3,6 +3,7 @@
     ReallySave :            "Realmente guardar?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "¡Tu sesión ha terminado!\nHas sido desconectado debido a una larga inactividad.\n1. Guarda tus ediciones del formulario en un archivo de texto para evitar pérdidas.\n2. Actualice la página.\n3. Inicie sesión de nuevo y vuelva a enviar.",
 
     // wikiedit.js
     HelpAbout :                "Ayuda & Acerca de",
diff --git a/wacko/js/lang/wikiedit.et.js b/wacko/js/lang/wikiedit.et.js
index b24c04d..b7bc472 100644
--- a/wacko/js/lang/wikiedit.et.js
+++ b/wacko/js/lang/wikiedit.et.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Sinu sessioon on aegunud!\nPika passiivsuse tõttu olete logitud välja.\n1. Kaotuse vältimiseks salvestage vormimuudatused tekstifaili.\n2. Värskendage lehte.\n3. Logi uuesti sisse ja esita uuesti.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.fr.js b/wacko/js/lang/wikiedit.fr.js
index 6007bed..ead2d89 100644
--- a/wacko/js/lang/wikiedit.fr.js
+++ b/wacko/js/lang/wikiedit.fr.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Votre session a expiré !\nVous avez été déconnecté en raison d'une longue inactivité.\n1. Enregistrez vos modifications de formulaire dans un fichier texte pour éviter toute perte.\n2. Rafraîchissez la page.\n3. Connectez-vous à nouveau et soumettez à nouveau.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.hu.js b/wacko/js/lang/wikiedit.hu.js
index cc516bf..f50d2b4 100644
--- a/wacko/js/lang/wikiedit.hu.js
+++ b/wacko/js/lang/wikiedit.hu.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "A munkamenet lejárt!\nA hosszú tétlenség miatt bejelentkezett.\n1. Az elvesztés elkerülése érdekében az űrlapszerkesztéseket szöveges fájlba mentse.\n2. Frissítsd az oldalt.\n3. Jelentkezzen be újra, és küldje el újra.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.it.js b/wacko/js/lang/wikiedit.it.js
index a7a9fe3..884bfbf 100644
--- a/wacko/js/lang/wikiedit.it.js
+++ b/wacko/js/lang/wikiedit.it.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "La tua sessione è scaduta!\nSei stato disconnesso a causa di una lunga inattività.\n1. Salva il tuo modulo modificato in un file di testo per evitare perdite.\n2. Aggiorna la pagina.\n3. Effettuare di nuovo il login e ripresentarsi.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.nl.js b/wacko/js/lang/wikiedit.nl.js
index 4dce9b9..71b1074 100644
--- a/wacko/js/lang/wikiedit.nl.js
+++ b/wacko/js/lang/wikiedit.nl.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Je sessie is verlopen!\nJe bent afgemeld vanwege lange inactiviteit.\n1. Sla je formulier op in een sms-bestand om verlies te voorkomen.\n2. Vernieuw de pagina.\n3. Log opnieuw in en dien opnieuw in.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.pl.js b/wacko/js/lang/wikiedit.pl.js
index 4afd296..226e49f 100644
--- a/wacko/js/lang/wikiedit.pl.js
+++ b/wacko/js/lang/wikiedit.pl.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Twoja sesja wygasła!\nZostałeś wylogowany z powodu długiej nieaktywności.\n1. Zapisz edycję formularza w pliku tekstowym, żeby zapobiec utracie.\n2. Odśwież stronę.\n3. Zaloguj się ponownie i prześlij ponownie.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.pt.js b/wacko/js/lang/wikiedit.pt.js
index 58101bd..76228e3 100644
--- a/wacko/js/lang/wikiedit.pt.js
+++ b/wacko/js/lang/wikiedit.pt.js
@@ -3,6 +3,7 @@
     ReallySave :            "Really save?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "A sua sessão expirou!\nVocê foi desconectado devido a uma longa inatividade.\n1. Guarde as edições do seu formulário no ficheiro de texto para evitar a sua perda.\n2. Actualize a página.\n3. Faça novamente o login e volte a enviar.",
 
     // wikiedit.js
     HelpAbout :                "Help & About",
diff --git a/wacko/js/lang/wikiedit.ru.js b/wacko/js/lang/wikiedit.ru.js
index 6a88729..0040817 100644
--- a/wacko/js/lang/wikiedit.ru.js
+++ b/wacko/js/lang/wikiedit.ru.js
@@ -3,6 +3,7 @@
     ReallySave :            "Действительно сохранить?",
     ModifiedHint :            "Field has changed, do not forget to save the changes.",
     NotSavedWarning :        "You did not save changes. Are you sure you want to leave?",
+    SessionExpiredEditor :    "Ваша сессия истекла!\nВаш сеанс работы с системой завершен из-за долгой неактивности.\n1. Сохраните введенные данные в текстовый файл, чтобы избежать их потери.\n2. Обновите страницу.\n3. Войдите в систему и отправьте данные повторно.",
 
     // wikiedit.js
     HelpAbout :                "Справка и о программе",

Show Files (3 files)