// swad.js: javascript functions /* SWAD (Shared Workspace At a Distance), is a web platform developed at the University of Granada (Spain), and used to support university teaching. Copyright (C) 1999-2023 Antonio Cañas-Vargas University of Granada (SPAIN) (acanas@ugr.es) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ "use strict"; // Global variable (string) used to write HTML var Gbl_HTMLContent; // Global variable used to call SWAD via AJAX var actionAJAX; /*****************************************************************************/ /************************** Handle match keystrokes **************************/ /*****************************************************************************/ function handleMatchKeys(event) { switch (event.key) { case 'PageUp': case 'ArrowLeft': case 'ArrowUp': submitForm('backward'); break; case ' ': // Space submitForm('play_pause'); break; case 'PageDown': case 'ArrowRight': case 'ArrowDown': submitForm('forward'); break; } } /*****************************************************************************/ /************************ Submit a form given its id *************************/ /*****************************************************************************/ function submitForm(FormId) { var Form = document.getElementById(FormId); if (Form) Form.submit(); return false; } /*****************************************************************************/ /*************** Write a date-time in client local time **********************/ /*****************************************************************************/ // id is the id of the HTML element in which date-time will be written // TimeUTC is the date-time to write in UTC UNIX time format // DateFormat: // Dat_FORMAT_YYYY_MM_DD = 0 // Dat_FORMAT_DD_MONTH_YYYY = 1 // Dat_FORMAT_MONTH_DD_YYYY = 2 // separator is HTML code to write between date and time // StrToday is a string in current language ('today', 'hoy'...) // WriteDateOnSameDay = false ==> don't write date if it's the same day than the last call // WriteWeekDay = true ==> write day of the week ('monday', 'tuesday'...) // WriteHMS = 3 least significant bits for hour, minute and second var txtToday = [ "", // Unknown "Avui", // CA "Heute", // DE "Today", // EN "Hoy", // ES "Aujourd'hui", // FR "Ko ára", // GN "Oggi", // IT "Dzisiaj", // PL "Hoje", // PT ]; function writeLocalDateHMSFromUTC (id,TimeUTC,DateFormat,Separator,Language, WriteToday,WriteDateOnSameDay,WriteWeekDay,WriteHMS) { // HMS: Hour, Minutes, Seconds var today = new Date(); var todayYea = today.getFullYear (); var todayMon = today.getMonth () + 1; var todayDay = today.getDate (); var d = new Date(); var WriteDate; var Yea,Mon,Day; var DayOfWeek; var Hou,Min,Sec; var StrDat; var StrMon; var StrDay; var StrHou; var StrMin; var StrSec; d.setTime (TimeUTC * 1000); Yea = d.getFullYear (); Mon = d.getMonth () + 1; Day = d.getDate (); if (WriteDateOnSameDay) WriteDate = true; // Check to see if the last date has been initialized else if (typeof writeLocalDateHMSFromUTC.lastd == 'undefined') // lastd: static variable to remember current date for the next call // Not initialized WriteDate = true; else WriteDate = (Yea != writeLocalDateHMSFromUTC.lastd.getFullYear () || Mon != writeLocalDateHMSFromUTC.lastd.getMonth () + 1 || Day != writeLocalDateHMSFromUTC.lastd.getDate ()); writeLocalDateHMSFromUTC.lastd = d; // Update last date for the next call /* Set date */ StrDat = ''; if (WriteDate) { WriteToday = WriteToday && (Yea == todayYea && Mon == todayMon && Day == todayDay); // Date is today if (WriteToday) StrDat = txtToday[Language]; else switch (DateFormat) { case 0: // Dat_FORMAT_YYYY_MM_DD StrMon = ((Mon < 10) ? '0' : '') + Mon; StrDay = ((Day < 10) ? '0' : '') + Day; StrDat = Yea.toString () + '-' + StrMon + '-' + StrDay; break; case 1: // Dat_FORMAT_DD_MONTH_YYYY StrDat = Day.toString () + ' ' + MonthsShort[Mon - 1] + ' ' + Yea.toString (); break; case 2: // Dat_FORMAT_MONTH_DD_YYYY StrDat = MonthsShort[Mon - 1] + ' ' + Day.toString() + ', ' + Yea.toString (); break; default: break; } if (WriteWeekDay) { DayOfWeek = d.getDay(); DayOfWeek = (DayOfWeek == 0) ? 6 : DayOfWeek - 1; StrDat += Separator + DAYS[DayOfWeek]; } StrDat += Separator; } /* Set HH:MM:SS */ StrHou = ''; StrMin = ''; StrSec = ''; if (WriteHMS & (1<<2)) { // Bit 2 on => Write hour Hou = d.getHours(); StrHou = ((Hou < 10) ? '0' : '') + Hou; if (WriteHMS & (1<<1)) { // Bits 2,1 on => Write minutes Min = d.getMinutes (); StrMin = ((Min < 10) ? ':0' : ':') + Min; if (WriteHMS & 1) { // Bits 2,1,0 on => Write seconds Sec = d.getSeconds (); StrSec = ((Sec < 10) ? ':0' : ':') + Sec; } } } /* Write date and time */ document.getElementById (id).innerHTML = StrDat + StrHou + StrMin + StrSec; } /*****************************************************************************/ /************** Set local date-time form fields from UTC time ****************/ /*****************************************************************************/ function setLocalDateTimeFormFromUTC (id,TimeUTC) { var FormYea = document.getElementById(id+'Year' ); var FormMon = document.getElementById(id+'Month' ); var FormDay = document.getElementById(id+'Day' ); var FormHou = document.getElementById(id+'Hour' ); var FormMin = document.getElementById(id+'Minute'); var FormSec = document.getElementById(id+'Second'); var d; var Year; var YearIsValid = false; var Hou; var Min; var Sec; if (TimeUTC) { d = new Date(); d.setTime(TimeUTC * 1000); Year = d.getFullYear(); for (var i=0; i=0; i--) if (FormMin.options[i].value <= Min) { FormMin.options[i].selected = true; break; } if (FormSec) { Sec = d.getSeconds(); FormSec.options[d.getSeconds()].selected = true; } } } if (!YearIsValid) { FormYea.options[0].selected = true; FormMon.options[0].selected = true; FormDay.options[0].selected = true; FormHou.options[0].selected = true; FormMin.options[0].selected = true; FormSec.options[0].selected = true; } } /*****************************************************************************/ /************** Set UTC time from local date-time form fields ****************/ /*****************************************************************************/ function setUTCFromLocalDateTimeForm (id) { var Seconds = 0; var idSecond = document.getElementById(id+'Second'); if (idSecond) // id+'Second' present Seconds = idSecond.value; // Important: set date all at once to avoid problems with different length of months var d = new Date(document.getElementById(id+'Year' ).value, document.getElementById(id+'Month' ).value-1, document.getElementById(id+'Day' ).value, document.getElementById(id+'Hour' ).value, document.getElementById(id+'Minute').value, Seconds, 0); document.getElementById(id+'TimeUTC').value = d.getTime() / 1000; } /*****************************************************************************/ /******************* Set form params related to time zones *******************/ /*****************************************************************************/ // Set form param with time difference between UTC time and client local time, in minutes // For example, if your time zone is GMT+2, -120 will be returned function setTZ (id) { var FormTZ = document.getElementById(id); var d = new Date(); FormTZ.value = d.getTimezoneOffset(); } // Set form param with the name of the time zone function setTZname (id) { var FormTZname = document.getElementById(id); var tz = jstz.determine(); // Determines the time zone of the browser client FormTZname.value = tz.name(); // Returns the name of the time zone eg "Europe/Berlin" } /*****************************************************************************/ /********* Adjust a date form correcting selector days in the month **********/ /*****************************************************************************/ // The selector of days can start by 1, 2, 3... or by -, 1, 2, 3... function adjustDateForm (id) { var FormYea = document.getElementById(id+'Year' ); var FormMon = document.getElementById(id+'Month'); var FormDay = document.getElementById(id+'Day' ); var Yea = Number(FormYea.options[FormYea.selectedIndex].value); var Mon = Number(FormMon.options[FormMon.selectedIndex].value); if (Yea != 0 && Mon != 0) { var LastDayIndex = FormDay.options.length - 1; var LastDayValue = Number(FormDay.options[LastDayIndex].value); var SelectedDay = Number(FormDay.options[FormDay.selectedIndex].value); var Days = daysInMonth (Mon,Yea); // If current selected day is out of range... if (SelectedDay > Days) // Select last day in month for (var i=LastDayIndex; i>=0; i--) if (FormDay.options[i].value == Days) { FormDay.options[i].selected = true; break; } // Create new days at the end if necessary for (var Day = Number(LastDayValue) + 1; Day <= Days; Day++) { var opt = document.createElement('option'); opt.value = opt.text = Day; FormDay.add(opt); } // Remove days from the end if necessary for (var i=LastDayIndex; i>=0; i--) if (FormDay.options[i].value > Days) FormDay.options[i] = null; else break; } } /*****************************************************************************/ /*********************** Get number of days in a month ***********************/ /*****************************************************************************/ function daysInMonth (month, year) { // Month is 1 based return new Date(year, month, 0).getDate(); // 0 is the last day of previous month } /*****************************************************************************/ /****************** Set a date range form to a specific day ******************/ /*****************************************************************************/ // Set a date range form to yesterday function setDateToYesterday (idStart,idEnd) { var d = new Date(); d.setTime (d.getTime () - 24 * 60 * 60 * 1000); // Today - 1 day setDateRange(idStart,idEnd,d); } // Set a date range form to today function setDateToToday (idStart,idEnd) { var d = new Date(); setDateRange(idStart,idEnd,d); } function setDateRange (idStart,idEnd,d) { var FormYea; var Yea = d.getFullYear(); var Mon = d.getMonth() + 1; var Day = d.getDate(); FormYea = document.getElementById(idStart+'Year'); for (var i=0; i= 60) { H = Math.floor(M / 60); M %= 60; } else H = 0; S = ListSeconds[i] % 60; if (H != 0) { StrM = ((M < 10) ? '0' : '') + M; StrS = ((S < 10) ? '0' : '') + S; PrintableClock = H + ':' + StrM + '′' + StrS + '″'; } else if (M != 0) { StrS = ((S < 10) ? '0' : '') + S; PrintableClock = M + '′' + StrS + '″'; } else PrintableClock = S + '″'; BoxClock.innerHTML = PrintableClock; } } } setTimeout('writeClockConnected()',1000); // refresh after 1 second } /*****************************************************************************/ /************* Automatic refresh of connected users using AJAX ***************/ /*****************************************************************************/ // This function must be called from time to time var objXMLHttpReqCon = false; function refreshConnected () { objXMLHttpReqCon = AJAXCreateObject(); if (objXMLHttpReqCon) { var refreshParams = refreshParamNxtActCon + '&' + refreshParamIdSes + '&' + refreshParamCrsCod; // onreadystatechange must be lowercase objXMLHttpReqCon.onreadystatechange = readConnUsrsData; objXMLHttpReqCon.open('POST',actionAJAX,true); objXMLHttpReqCon.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqCon.send(refreshParams); } } // Receive and show connected users data function readConnUsrsData () { if (objXMLHttpReqCon.readyState == 4) // Check if data have been received if (objXMLHttpReqCon.status == 200) { var endOfDelay = objXMLHttpReqCon.responseText.indexOf('|',0); // Get separator position var endOfNotif = objXMLHttpReqCon.responseText.indexOf('|',endOfDelay + 1); // Get separator position var endOfGblCon = objXMLHttpReqCon.responseText.indexOf('|',endOfNotif + 1); // Get separator position var endOfCrsCon = objXMLHttpReqCon.responseText.indexOf('|',endOfGblCon + 1); // Get separator position var endOfNumUsrs = objXMLHttpReqCon.responseText.indexOf('|',endOfCrsCon + 1); // Get separator position var delay = parseInt(objXMLHttpReqCon.responseText.substring(0,endOfDelay)); // Get refresh delay var htmlNotif = objXMLHttpReqCon.responseText.substring(endOfDelay + 1,endOfNotif); // Get HTML code for new notifications var htmlGblCon = objXMLHttpReqCon.responseText.substring(endOfNotif + 1,endOfGblCon); // Get HTML code for connected var htmlCrsCon = objXMLHttpReqCon.responseText.substring(endOfGblCon + 1,endOfCrsCon); // Get HTML code for course connected var NumUsrsStr = objXMLHttpReqCon.responseText.substring(endOfCrsCon + 1,endOfNumUsrs); // Get number of users var startOfUsr; var endOfUsr; NumUsrsCon = (NumUsrsStr.length ? parseInt(NumUsrsStr) : 0); var divNewNotif = document.getElementById('msg'); // Access to new notifications DIV if (divNewNotif) divNewNotif.innerHTML = (htmlNotif.length) ? htmlNotif : ''; // Update new notifications DIV var divGblConnected = document.getElementById('globalconnected'); // Access to global connected DIV if (divGblConnected) divGblConnected.innerHTML = htmlGblCon; // Update global connected DIV if (htmlCrsCon.length) { var divCrsConnected = document.getElementById('courseconnected'); // Access to course connected DIV if (divCrsConnected) { divCrsConnected.innerHTML = htmlCrsCon; // Update course connected DIV countClockConnected = 0; // Don't refresh again using writeClockConnected until past 10 seconds startOfUsr = endOfNumUsrs + 1; for (var NumUsr=0; NumUsr= 60000) // If refresh slower than 1 time each 60 seconds, do refresh; else abort setTimeout('refreshConnected()',delay); } } /*****************************************************************************/ /***************** Update exam print main area using AJAX ********************/ /*****************************************************************************/ var txtConnectionIssues = [ "", // Unknown "Problemes de connexió. Els canvis no s'han desat.", // CA "Verbindungsprobleme. Die Änderungen wurden nicht gespeichert.", // DE "Connection issues. The changes have not been saved.", // EN "Problema de conexión. Los cambios no se han guardado.", // ES "Problèmes de connexion. Les modifications n'ont pas été enregistrées.",// FR "Problema de conexión. Los cambios no se han guardado.", // GN Okoteve traducción "Problemi di connessione. Le modifiche non sono state salvate.", // IT "Problemy z połączeniem. Zmiany nie zostały zapisane.", // PL "Problemas de conexão. As alterações não foram salvas." // PT ]; var txtSaving = [ "", // Unknown "Desant…", // CA "Speichern…", // DE "Saving…", // EN "Guardando…", // ES "Enregistrement…", // FR "Guardando…", // GN Okoteve traducción "Salvataggio…", // IT "Zapisywanie…", // PL "Salvando…", // PT ]; var IHaveFinishedTxt; // This function is called when user changes an answer in an exam print function updateExamPrint (idDiv,idInput,nameInput,Params,Language) { var objXMLHttp = false; objXMLHttp = AJAXCreateObject (); if (objXMLHttp) { /* Send request to server */ // onreadystatechange must be lowercase objXMLHttp.onreadystatechange = function() { if (objXMLHttp.readyState == 4) // Check if data have been received if (objXMLHttp.status == 200) { // Response received clearTimeout (xmlHttpTimeout); // Clear timeout if (idDiv) { var div = document.getElementById(idDiv); // Access to DIV if (div) { div.innerHTML = objXMLHttp.responseText; // Update DIV content // Scripts in div got via AJAX are not executed ==> execute them evalScriptsInElem (div); // Process maths; see http://docs.mathjax.org/en/latest/advanced/typeset.html MathJax.typeset(); } } } }; var inputElem = document.getElementById(idInput); if (inputElem) if (inputElem.type) { if (inputElem.type === 'radio') { if (inputElem.checked) Params += '&' + nameInput + '=' + inputElem.value; } else if (inputElem.type === 'checkbox') { var inputElems = inputElem.form.elements; var i = 0; // First checkbox checked for (; i user will see ? input } } IHaveFinishedTxt = disableFinished (txtSaving[Language]); // Disable finished button on sending. When answer is saved and response received ==> the button will be reloaded objXMLHttp.open('POST',actionAJAX,true); objXMLHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttp.send(Params); /* Timeout to abort in 5 seconds. See https://stackoverflow.com/questions/1018705/how-to-detect-timeout-on-an-ajax-xmlhttprequest-call-in-the-browser and http://geekswithblogs.net/lorint/archive/2006/03/07/71625.aspx "ontimeout" based solutions does not work when network disconnects */ var xmlHttpTimeout = setTimeout (ajaxTimeout,5000); // 5 s function ajaxTimeout () { objXMLHttp.abort (); alert (txtConnectionIssues[Language]); disableFinished (IHaveFinishedTxt); // Sending aborted ==> change "Saving..." to original "I have finished" }; } } // Escape the same chars as encodeURIComponent(), but in ISO-8859-1 function getEscapedString (str) { const len = str.length; var escaped = ''; for (var i = 0; i < len; i++) { const code = str.charCodeAt(i); switch (true) { // Escape punctuation marks except - _ . ! ~ * ' ( ) case (code <= 0x09): // Spec. escaped += '%0' + code.toString(16).toUpperCase(); // %0X break; case (code >= 0x10 && code <= 0x20): // Spec. 0x20 space case (code >= 0x22 && code <= 0x26): // 0x22 " 0x23 # 0x24 $ 0x25 % 0x26 & case (code == 0x2B): // 0x2B + case (code == 0x2C): // 0x2C , case (code == 0x2F): // 0x2F / case (code >= 0x3A && code <= 0x40): // 0x3A : 0x3B ; 0x3C < 0x3D = 0x3E > 0x3F ? 0x40 @ case (code >= 0x5B && code <= 0x5E): // 0x5B [ 0x5C \ 0x5D ] 0x5E ^ case (code == 0x60): // 0x60 ` case (code >= 0x7B && code <= 0x7D): // 0x7B { 0x7C | 0x7D } case (code >= 0x7F && code <= 0xFF): // ISO-8859-1 or windows-1252 escaped += '%' + code.toString(16).toUpperCase(); // %XX break; case (code >= 0x100): escaped += '%26%23' + code.toString(10) + '%3B'; // &#code; instead of %uXXXX break; default: // 0x21 ! // 0x27 ' 0x28 ( 0x29 ) 0x2A * // 0x2D - 0x2E . // 0x30 0 ... 0x39 9 // 0x41 A ... 0x5A Z // 0x5F _ // 0x61 a ... 0x7A z // 0x7E ~ escaped += str.charAt(i); break; } } return escaped; } /* // To generate a table with the codification generated by encodeURIComponent() // and escape(), copy the following code in https://playcode.io/ //----------------------------------------------------------------------------- var arr = []; for(var i=0;i<256;i++) { var char=String.fromCharCode(i); arr.push({ character:char, encodeURIComponent:encodeURIComponent(char), escape:escape(char) }); } console.table(arr); //----------------------------------------------------------------------------- */ /*****************************************************************************/ /********* Disable button to finish exam when focus on a input text **********/ /*****************************************************************************/ function disableFinished (buttonNewTxt) { var f = document.getElementById('finished'); // Access to form var buttonOldTxt = ''; if (f) for (var i = 0; i < f.elements.length; i++) { var b = f.elements[i]; if (b.type == 'submit') { b.disabled = true; b.style.opacity = 0.5; buttonOldTxt = b.innerHTML; b.innerHTML = buttonNewTxt; } } return buttonOldTxt; } /*****************************************************************************/ /********** Automatic refresh of current match question using AJAX ***********/ /*****************************************************************************/ // This function must be called from time to time var objXMLHttpReqMchStd = false; function refreshMatchStd () { objXMLHttpReqMchStd = AJAXCreateObject(); if (objXMLHttpReqMchStd) { var refreshParams = refreshParamNxtActMch + '&' + refreshParamMchCod + '&' + refreshParamIdSes; // onreadystatechange must be lowercase objXMLHttpReqMchStd.onreadystatechange = readMatchStdData; objXMLHttpReqMchStd.open('POST',actionAJAX,true); objXMLHttpReqMchStd.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqMchStd.send(refreshParams); } } function readMatchStdData () { if (objXMLHttpReqMchStd.readyState == 4) // Check if data have been received if (objXMLHttpReqMchStd.status == 200) { var htmlMatch = objXMLHttpReqMchStd.responseText; // Get HTML code var div = document.getElementById('match'); // Access to refreshable DIV if (div) div.innerHTML = htmlMatch; // Update DIV content // Global delay variable is set initially in swad-core setTimeout('refreshMatchStd()',delayMatch); } } /*****************************************************************************/ /**** Automatic refresh of left part of current match question using AJAX ****/ /*****************************************************************************/ //This function must be called from time to time var objXMLHttpReqMchTch = false; function refreshMatchTch () { objXMLHttpReqMchTch = AJAXCreateObject(); if (objXMLHttpReqMchTch) { var refreshParams = refreshParamNxtActMch + '&' + refreshParamMchCod + '&' + refreshParamIdSes; // onreadystatechange must be lowercase objXMLHttpReqMchTch.onreadystatechange = readMatchTchData; objXMLHttpReqMchTch.open('POST',actionAJAX,true); objXMLHttpReqMchTch.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqMchTch.send(refreshParams); } } function readMatchTchData () { if (objXMLHttpReqMchTch.readyState == 4) // Check if data have been received if (objXMLHttpReqMchTch.status == 200) { var endOfId = objXMLHttpReqMchTch.responseText.indexOf('|',0 ); // Get separator position var endOfEv = objXMLHttpReqMchTch.responseText.indexOf('|',endOfId + 1); // Get separator position var id = objXMLHttpReqMchTch.responseText.substring(0 ,endOfId); // Get id var ev = objXMLHttpReqMchTch.responseText.substring(endOfId + 1,endOfEv); // Get ev ('0' / '1') var html = objXMLHttpReqMchTch.responseText.substring(endOfEv + 1); // Get HTML code var div = document.getElementById(id); // Access to refreshable DIV if (div) { div.innerHTML = html; // Update DIV content if (parseInt(ev)) { // 0 / 1 // Scripts in div got via AJAX are not executed ==> execute them evalScriptsInElem (div); // Process maths; see http://docs.mathjax.org/en/latest/advanced/typeset.html MathJax.typeset(); } } // Global delay variable is set initially in swad-core setTimeout('refreshMatchTch()',delayMatch); } } /*****************************************************************************/ /****************** Update match control area using AJAX *********************/ /*****************************************************************************/ // This function is called when user submit a form inside two parent divs function updateMatchTch (id,Params) { var objXMLHttp = false; objXMLHttp = AJAXCreateObject (); if (objXMLHttp) { /* Send request to server */ // onreadystatechange must be lowercase objXMLHttp.onreadystatechange = function() { if (objXMLHttp.readyState == 4) // Check if data have been received if (objXMLHttp.status == 200) if (id) { var div = document.getElementById(id); // Access to DIV if (div) div.innerHTML = objXMLHttp.responseText; // Update DIV content } }; objXMLHttp.open('POST',actionAJAX,true); objXMLHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttp.send(Params); } } /*****************************************************************************/ /**************** Automatic refresh of last clicks using AJAX ****************/ /*****************************************************************************/ // This function must be called from time to time var objXMLHttpReqLog = false; function refreshLastClicks () { objXMLHttpReqLog = AJAXCreateObject(); if (objXMLHttpReqLog) { var refreshParams = refreshParamNxtActLstClk + '&' + refreshParamIdSes + '&' + refreshParamCrsCod; // onreadystatechange must be lowercase objXMLHttpReqLog.onreadystatechange = readLastClicksData; objXMLHttpReqLog.open('POST',actionAJAX,true); objXMLHttpReqLog.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqLog.send(refreshParams); } } function readLastClicksData () { if (objXMLHttpReqLog.readyState == 4) // Check if data have been received if (objXMLHttpReqLog.status == 200) { var endOfDelay = objXMLHttpReqLog.responseText.indexOf('|',0); // Get separator position var delay = parseInt(objXMLHttpReqLog.responseText.substring(0,endOfDelay)); // Get refresh delay var htmlLastClicks = objXMLHttpReqLog.responseText.substring(endOfDelay + 1); // Get HTML code for last clicks var divLastClicks = document.getElementById('lastclicks'); // Access to last click DIV if (divLastClicks) divLastClicks.innerHTML = htmlLastClicks; // Update global connected DIV if (delay > 200) // If refresh slower than 1 time each 0.2 seconds, do refresh; else abort setTimeout('refreshLastClicks()',delay); } } /*****************************************************************************/ /******* Automatically refresh new publications in timeline using AJAX *******/ /*****************************************************************************/ // This function must be called from time to time var objXMLHttpReqNewTml = false; function refreshNewTimeline () { objXMLHttpReqNewTml = AJAXCreateObject(); if (objXMLHttpReqNewTml) { var refreshParams = refreshParamNxtActNewPub + '&' + refreshParamIdSes + '&' + refreshParamWho; // onreadystatechange must be lowercase objXMLHttpReqNewTml.onreadystatechange = readNewTimelineData; objXMLHttpReqNewTml.open('POST',actionAJAX,true); objXMLHttpReqNewTml.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); objXMLHttpReqNewTml.send(refreshParams); } } function readNewTimelineData () { if (objXMLHttpReqNewTml.readyState == 4) // Check if data have been received if (objXMLHttpReqNewTml.status == 200) { // Access to UL for just now timeline var justNowTimeline = document.getElementById('just_now_timeline_list'); if (justNowTimeline) { // Update list of publications in just now timeline justNowTimeline.innerHTML = objXMLHttpReqNewTml.responseText; var numNotesJustGot = justNowTimeline.childNodes.length; if (numNotesJustGot) { // New notes received // Scripts in timeline got via AJAX not executed ==> execute them evalScriptsInElem (justNowTimeline); // Process maths; see http://docs.mathjax.org/en/latest/advanced/typeset.html MathJax.typeset(); // Move all the LI elements (notes) in UL 'just_now_timeline_list'... // ...to the top of UL 'new_timeline_list' var newTimeline = document.getElementById('new_timeline_list'); for (var i=0; i