From e5187b7994b4208b6cfb663489188f4624eff7e5 Mon Sep 17 00:00:00 2001 From: acanas Date: Fri, 15 May 2020 22:00:14 +0200 Subject: [PATCH] Version19.230.3 --- js/swad19.230.3.js | 1996 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1996 insertions(+) create mode 100644 js/swad19.230.3.js diff --git a/js/swad19.230.3.js b/js/swad19.230.3.js new file mode 100644 index 000000000..6c84fb554 --- /dev/null +++ b/js/swad19.230.3.js @@ -0,0 +1,1996 @@ +// 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-2020 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 + +function writeLocalDateHMSFromUTC (id,TimeUTC,DateFormat,Separator,StrToday, + 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 WriteTodayStr; + var Yea; + var Mon; + var Day; + var DayOfWeek; + var Hou; + var Min; + var Sec; + var StrDate; + 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') // 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 */ + StrDate = ''; + if (WriteDate) { + WriteTodayStr = false; + if (StrToday != null) + if (StrToday.length && + Yea == todayYea && + Mon == todayMon && + Day == todayDay) // Today + WriteTodayStr = true; + + if (WriteTodayStr) + StrDate = StrToday; + else + switch (DateFormat) { + case 0: // Dat_FORMAT_YYYY_MM_DD + StrMon = ((Mon < 10) ? '0' : '') + Mon; + StrDay = ((Day < 10) ? '0' : '') + Day; + StrDate = Yea.toString() + '-' + StrMon + '-' + StrDay; + break; + case 1: // Dat_FORMAT_DD_MONTH_YYYY + StrDate = Day.toString() + ' ' + MonthsShort[Mon - 1] + ' ' + Yea.toString(); + break; + case 2: // Dat_FORMAT_MONTH_DD_YYYY + StrDate = MonthsShort[Mon - 1] + ' ' + Day.toString() + ', ' + Yea.toString(); + break; + default: + break; + } + + if (WriteWeekDay) { + DayOfWeek = d.getDay(); + DayOfWeek = (DayOfWeek == 0) ? 6 : DayOfWeek - 1; + StrDate = StrDate + Separator + DAYS[DayOfWeek]; + } + } + else if (WriteWeekDay) + StrDate = Separator; + StrDate = StrDate + 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 = StrDate + 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; + + objXMLHttpReqCon.onreadystatechange = readConnUsrsData; // onreadystatechange must be lowercase + 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 ********************/ +/*****************************************************************************/ + +// This function is called when user changes an answer in an exam print +function updateExamPrint (idDiv,idInput,nameInput,Params) { + var objXMLHttp = false; + + objXMLHttp = AJAXCreateObject (); + if (objXMLHttp) { + /* Send request to server */ + objXMLHttp.onreadystatechange = function() { // onreadystatechange must be lowercase + if (objXMLHttp.readyState == 4) // Check if data have been received + if (objXMLHttp.status == 200) + 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 mathematics; see http://docs.mathjax.org/en/latest/advanced/typeset.html + // MathJax.Hub.Queue(["Typeset",MathJax.Hub,div]); // old versions + 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 execute them + evalScriptsInElem (div); + + // Process mathematics; see http://docs.mathjax.org/en/latest/advanced/typeset.html + // MathJax.Hub.Queue(["Typeset",MathJax.Hub,div]); // old versions + 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 */ + objXMLHttp.onreadystatechange = function() { // onreadystatechange must be lowercase + 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; + + objXMLHttpReqLog.onreadystatechange = readLastClicksData; // onreadystatechange must be lowercase + 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 social timeline using AJAX ****/ +/*****************************************************************************/ + +// This function must be called from time to time +var objXMLHttpReqNewTL = false; +function refreshNewTL () { + objXMLHttpReqNewTL = AJAXCreateObject(); + if (objXMLHttpReqNewTL) { + var RefreshParams = RefreshParamNxtActNewPub + '&' + + RefreshParamIdSes + '&' + + RefreshParamWho; + + objXMLHttpReqNewTL.onreadystatechange = readNewTimelineData; // onreadystatechange must be lowercase + objXMLHttpReqNewTL.open('POST',ActionAJAX,true); + objXMLHttpReqNewTL.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); + objXMLHttpReqNewTL.send(RefreshParams); + } +} + +// Receive and show new social timeline data +function readNewTimelineData () { + if (objXMLHttpReqNewTL.readyState == 4) { // Check if data have been received + if (objXMLHttpReqNewTL.status == 200) { + + var justNowTimeline = document.getElementById('just_now_timeline_list');// Access to UL for the just received timeline + if (justNowTimeline) { + justNowTimeline.innerHTML = objXMLHttpReqNewTL.responseText; // Update list of publications in just now timeline + + var countJustNowTimeline = justNowTimeline.childNodes.length; + if (countJustNowTimeline) { // New pubs just retrieved + // Scripts in timeline got via AJAX are not executed ==> execute them + evalScriptsInElem (justNowTimeline); + + // Process mathematics; see http://docs.mathjax.org/en/latest/advanced/typeset.html + // MathJax.Hub.Queue(["Typeset",MathJax.Hub,justNowTimeline]); // old versions + MathJax.typeset(); + + // Move just received timeline to top of new timeline + var newTimeline = document.getElementById('new_timeline_list'); // Access to UL with the new timeline + + // Move all the LI elements in UL 'just_now_timeline_list' to the top of UL 'new_timeline_list' + for (var i=0; i