diff --git a/js/swad19.236.4.js b/js/swad19.238.3.js
similarity index 99%
rename from js/swad19.236.4.js
rename to js/swad19.238.3.js
index 8680b0df8..ec87ec681 100644
--- a/js/swad19.236.4.js
+++ b/js/swad19.238.3.js
@@ -550,15 +550,16 @@ function readConnUsrsData () {
/*****************************************************************************/
// This function is called when user changes an answer in an exam print
-function updateExamPrint (idDiv,idInput,nameInput,Params) {
+function updateExamPrint (idDiv,idInput,nameInput,Params,timeoutMsg) {
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 (objXMLHttp.readyState == 4) { // Check if data have been received
+ if (objXMLHttp.status == 200) {
+ clearTimeout (xmlHttpTimeout); // Response received ==> clear timeout
if (idDiv) {
var div = document.getElementById(idDiv); // Access to DIV
if (div) {
@@ -572,6 +573,8 @@ function updateExamPrint (idDiv,idInput,nameInput,Params) {
MathJax.typeset();
}
}
+ }
+ }
};
var inputElem = document.getElementById(idInput);
@@ -606,6 +609,16 @@ function updateExamPrint (idDiv,idInput,nameInput,Params) {
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 (timeoutMsg);
+ };
}
}
diff --git a/swad_changelog.h b/swad_changelog.h
index 1e3fb0b7e..9785c65e6 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -557,10 +557,11 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD:
ps2pdf source.ps destination.pdf
*/
-#define Log_PLATFORM_VERSION "SWAD 19.238.2 (2020-05-18)"
+#define Log_PLATFORM_VERSION "SWAD 19.238.3 (2020-05-19)"
#define CSS_FILE "swad19.238.2.css"
-#define JS_FILE "swad19.236.4.js"
+#define JS_FILE "swad19.238.3.js"
/*
+ Version 19.238.3: May 19, 2020 Fixed issue due to network timeout while answering exams. Reported by Nuria Torres Rosell. (301316 lines)
Version 19.238.2: May 19, 2020 Exam description is written in exam heading. Suggested by Eva Martínez Ortigosa. (301254 lines)
Version 19.238.1: May 19, 2020 Fixed bug: clicks on answers of exam prints are logged. (301566 lines)
Version 19.238: May 18, 2020 Fix exam-related details.
diff --git a/swad_exam_print.c b/swad_exam_print.c
index d952870d8..f3763d3d5 100644
--- a/swad_exam_print.c
+++ b/swad_exam_print.c
@@ -86,17 +86,22 @@ static void ExaPrn_WriteQstAndAnsToFill (const struct ExaPrn_Print *Print,
static void ExaPrn_WriteAnswersToFill (const struct ExaPrn_Print *Print,
unsigned NumQst,
const struct Tst_Question *Question);
+//-----------------------------------------------------------------------------
static void ExaPrn_WriteIntAnsToFill (const struct ExaPrn_Print *Print,
unsigned NumQst);
-static void ExaPrn_WriteFloatAnsToFill (const struct ExaPrn_Print *Print,
- unsigned NumQst);
-static void ExaPrn_WriteTFAnsToFill (const struct ExaPrn_Print *Print,
- unsigned NumQst);
-static void ExaPrn_WriteChoiceAnsToFill (const struct ExaPrn_Print *Print,
- unsigned NumQst,
- const struct Tst_Question *Question);
-static void ExaPrn_WriteTextAnsToFill (const struct ExaPrn_Print *Print,
- unsigned NumQst);
+static void ExaPrn_WriteFloAnsToFill (const struct ExaPrn_Print *Print,
+ unsigned NumQst);
+static void ExaPrn_WriteTF_AnsToFill (const struct ExaPrn_Print *Print,
+ unsigned NumQst);
+static void ExaPrn_WriteChoAnsToFill (const struct ExaPrn_Print *Print,
+ unsigned NumQst,
+ const struct Tst_Question *Question);
+static void ExaPrn_WriteTxtAnsToFill (const struct ExaPrn_Print *Print,
+ unsigned NumQst);
+//-----------------------------------------------------------------------------
+static void ExaPrn_WriteJSToUpdateExamPrint (const struct ExaPrn_Print *Print,
+ unsigned NumQst,
+ const char *Id,int NumOpt);
static unsigned ExaPrn_GetAnswerFromForm (struct ExaPrn_Print *Print);
@@ -736,17 +741,17 @@ static void ExaPrn_WriteAnswersToFill (const struct ExaPrn_Print *Print,
ExaPrn_WriteIntAnsToFill (Print,NumQst);
break;
case Tst_ANS_FLOAT:
- ExaPrn_WriteFloatAnsToFill (Print,NumQst);
+ ExaPrn_WriteFloAnsToFill (Print,NumQst);
break;
case Tst_ANS_TRUE_FALSE:
- ExaPrn_WriteTFAnsToFill (Print,NumQst);
+ ExaPrn_WriteTF_AnsToFill (Print,NumQst);
break;
case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE:
- ExaPrn_WriteChoiceAnsToFill (Print,NumQst,Question);
+ ExaPrn_WriteChoAnsToFill (Print,NumQst,Question);
break;
case Tst_ANS_TEXT:
- ExaPrn_WriteTextAnsToFill (Print,NumQst);
+ ExaPrn_WriteTxtAnsToFill (Print,NumQst);
break;
default:
break;
@@ -770,19 +775,16 @@ static void ExaPrn_WriteIntAnsToFill (const struct ExaPrn_Print *Print,
" size=\"11\" maxlength=\"11\" value=\"%s\"",
Id,
Print->PrintedQuestions[NumQst].StrAnswers);
- HTM_TxtF (" onchange=\"updateExamPrint('examprint','%s','Ans',"
- "'act=%ld&ses=%s&SesCod=%ld&NumQst=%u');"
- " return false;\" />", // return false is necessary to not submit form
- Id,
- Act_GetActCod (ActAnsExaPrn),Gbl.Session.Id,Print->SesCod,NumQst);
+ ExaPrn_WriteJSToUpdateExamPrint (Print,NumQst,Id,-1);
+ HTM_Txt (" />");
}
/*****************************************************************************/
/****************** Write float answer when seeing a test ********************/
/*****************************************************************************/
-static void ExaPrn_WriteFloatAnsToFill (const struct ExaPrn_Print *Print,
- unsigned NumQst)
+static void ExaPrn_WriteFloAnsToFill (const struct ExaPrn_Print *Print,
+ unsigned NumQst)
{
char Id[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
@@ -794,19 +796,16 @@ static void ExaPrn_WriteFloatAnsToFill (const struct ExaPrn_Print *Print,
" size=\"11\" maxlength=\"%u\" value=\"%s\"",
Id,Tst_MAX_BYTES_FLOAT_ANSWER,
Print->PrintedQuestions[NumQst].StrAnswers);
- HTM_TxtF (" onchange=\"updateExamPrint('examprint','%s','Ans',"
- "'act=%ld&ses=%s&SesCod=%ld&NumQst=%u');"
- " return false;\" />", // return false is necessary to not submit form
- Id,
- Act_GetActCod (ActAnsExaPrn),Gbl.Session.Id,Print->SesCod,NumQst);
+ ExaPrn_WriteJSToUpdateExamPrint (Print,NumQst,Id,-1);
+ HTM_Txt (" />");
}
/*****************************************************************************/
/************** Write false / true answer when seeing a test ****************/
/*****************************************************************************/
-static void ExaPrn_WriteTFAnsToFill (const struct ExaPrn_Print *Print,
- unsigned NumQst)
+static void ExaPrn_WriteTF_AnsToFill (const struct ExaPrn_Print *Print,
+ unsigned NumQst)
{
extern const char *Txt_TF_QST[2];
char Id[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
@@ -819,12 +818,8 @@ static void ExaPrn_WriteTFAnsToFill (const struct ExaPrn_Print *Print,
"Ans%010u",
NumQst);
HTM_TxtF ("", // return false is necessary to not submit form
- Id,
- Act_GetActCod (ActAnsExaPrn),
- Gbl.Session.Id,Print->SesCod,NumQst);
+ ExaPrn_WriteJSToUpdateExamPrint (Print,NumQst,Id,-1);
+ HTM_Txt (" />");
HTM_OPTION (HTM_Type_STRING,"" ,Print->PrintedQuestions[NumQst].StrAnswers[0] == '\0',false," ");
HTM_OPTION (HTM_Type_STRING,"T",Print->PrintedQuestions[NumQst].StrAnswers[0] == 'T' ,false,"%s",Txt_TF_QST[0]);
HTM_OPTION (HTM_Type_STRING,"F",Print->PrintedQuestions[NumQst].StrAnswers[0] == 'F' ,false,"%s",Txt_TF_QST[1]);
@@ -835,9 +830,9 @@ static void ExaPrn_WriteTFAnsToFill (const struct ExaPrn_Print *Print,
/******** Write single or multiple choice answer when seeing a test **********/
/*****************************************************************************/
-static void ExaPrn_WriteChoiceAnsToFill (const struct ExaPrn_Print *Print,
- unsigned NumQst,
- const struct Tst_Question *Question)
+static void ExaPrn_WriteChoAnsToFill (const struct ExaPrn_Print *Print,
+ unsigned NumQst,
+ const struct Tst_Question *Question)
{
unsigned NumOpt;
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
@@ -866,7 +861,6 @@ static void ExaPrn_WriteChoiceAnsToFill (const struct ExaPrn_Print *Print,
If the user does not confirm the submission of their exam ==>
==> the exam may be half filled ==> the answers displayed will be those selected by the user. */
HTM_TD_Begin ("class=\"LT\"");
-
snprintf (Id,sizeof (Id),
"Ans%010u",
NumQst);
@@ -876,11 +870,8 @@ static void ExaPrn_WriteChoiceAnsToFill (const struct ExaPrn_Print *Print,
Id,NumOpt,Indexes[NumOpt],
UsrAnswers[Indexes[NumOpt]] ? " checked=\"checked\"" :
"");
- HTM_TxtF (" onclick=\"updateExamPrint('examprint','%s_%u','Ans',"
- "'act=%ld&ses=%s&SesCod=%ld&NumQst=%u');"
- " return false;\" />", // return false is necessary to not submit form
- Id,NumOpt,
- Act_GetActCod (ActAnsExaPrn),Gbl.Session.Id,Print->SesCod,NumQst);
+ ExaPrn_WriteJSToUpdateExamPrint (Print,NumQst,Id,(int) NumOpt);
+ HTM_Txt (" />");
HTM_TD_End ();
HTM_TD_Begin ("class=\"LT\"");
@@ -910,8 +901,8 @@ static void ExaPrn_WriteChoiceAnsToFill (const struct ExaPrn_Print *Print,
/******************** Write text answer when seeing a test *******************/
/*****************************************************************************/
-static void ExaPrn_WriteTextAnsToFill (const struct ExaPrn_Print *Print,
- unsigned NumQst)
+static void ExaPrn_WriteTxtAnsToFill (const struct ExaPrn_Print *Print,
+ unsigned NumQst)
{
char Id[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
@@ -923,11 +914,33 @@ static void ExaPrn_WriteTextAnsToFill (const struct ExaPrn_Print *Print,
" size=\"40\" maxlength=\"%u\" value=\"%s\"",
Id,Tst_MAX_CHARS_ANSWERS_ONE_QST,
Print->PrintedQuestions[NumQst].StrAnswers);
- HTM_TxtF (" onchange=\"updateExamPrint('examprint','%s','Ans',"
- "'act=%ld&ses=%s&SesCod=%ld&NumQst=%u');"
- " return false;\" />", // return false is necessary to not submit form
- Id,
- Act_GetActCod (ActAnsExaPrn),Gbl.Session.Id,Print->SesCod,NumQst);
+ ExaPrn_WriteJSToUpdateExamPrint (Print,NumQst,Id,-1);
+ HTM_Txt (" />");
+ }
+
+/*****************************************************************************/
+/********************** Receive answer to an exam print **********************/
+/*****************************************************************************/
+
+static void ExaPrn_WriteJSToUpdateExamPrint (const struct ExaPrn_Print *Print,
+ unsigned NumQst,
+ const char *Id,int NumOpt)
+ {
+ extern const char *Txt_The_changes_have_not_been_saved_;
+
+ if (NumOpt < 0)
+ HTM_TxtF (" onchange=\"updateExamPrint('examprint','%s','Ans',"
+ "'act=%ld&ses=%s&SesCod=%ld&NumQst=%u','%s');",
+ Id,
+ Act_GetActCod (ActAnsExaPrn),Gbl.Session.Id,Print->SesCod,NumQst,
+ Txt_The_changes_have_not_been_saved_);
+ else // NumOpt >= 0
+ HTM_TxtF (" onclick=\"updateExamPrint('examprint','%s_%d','Ans',"
+ "'act=%ld&ses=%s&SesCod=%ld&NumQst=%u','%s');",
+ Id,NumOpt,
+ Act_GetActCod (ActAnsExaPrn),Gbl.Session.Id,Print->SesCod,NumQst,
+ Txt_The_changes_have_not_been_saved_);
+ HTM_Txt (" return false;\""); // return false is necessary to not submit form
}
/*****************************************************************************/
diff --git a/swad_text.c b/swad_text.c
index 910ea5ee9..0aef95c71 100644
--- a/swad_text.c
+++ b/swad_text.c
@@ -46312,6 +46312,45 @@ const char *Txt_The_centre_X_has_been_renamed_as_Y = // Warning: it is very impo
"O centro %s foi renomeado como %s.";
#endif
+const char *Txt_The_changes_have_not_been_saved_ =
+#if L==1 // ca
+ "Els canvis no s'han desat."
+ " És possible que el servidor estigui trigant a respondre"
+ " o que hi hagi problemes en la connexió de xarxa.";
+#elif L==2 // de
+ "Die Änderungen wurden nicht gespeichert."
+ " Der Server reagiert möglicherweise nur langsam"
+ " oder es treten Probleme mit Ihrer Netzwerkverbindung auf.";
+#elif L==3 // en
+ "The changes have not been saved."
+ " The server may be slow to respond"
+ " or there may be problems with your network connection.";
+#elif L==4 // es
+ "Los cambios no se han guardado."
+ " Es posible que el servidor esté tardando en responder"
+ " o que haya problemas en la conexión de red.";
+#elif L==5 // fr
+ "Les modifications n'ont pas été enregistrées."
+ " Le serveur peut être lent à répondre"
+ " ou il peut y avoir des problèmes avec votre connexion réseau.";
+#elif L==6 // gn
+ "Los cambios no se han guardado."
+ " Es posible que el servidor esté tardando en responder"
+ " o que haya problemas en la conexión de red."; // Okoteve traducción
+#elif L==7 // it
+ "Le modifiche non sono state salvate."
+ " Il server potrebbe rispondere lentamente"
+ " o potrebbero esserci problemi con la connessione di rete.";
+#elif L==8 // pl
+ "Zmiany nie zostały zapisane."
+ " Serwer może długo reagować"
+ " lub mogą występować problemy z poł&atrok;czeniem sieciowym.";
+#elif L==9 // pt
+ "As alterações não foram salvas."
+ " O servidor pode demorar para responder"
+ " ou pode haver problemas com sua conexão de rede.";
+#endif
+
const char *Txt_The_comment_no_longer_exists =
#if L==1 // ca
"El comentari ja no existeix.";