summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/acrotex/exerquiz.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/acrotex/exerquiz.dtx')
-rw-r--r--macros/latex/contrib/acrotex/exerquiz.dtx523
1 files changed, 365 insertions, 158 deletions
diff --git a/macros/latex/contrib/acrotex/exerquiz.dtx b/macros/latex/contrib/acrotex/exerquiz.dtx
index 7a7a0fdb5d..d73c3efdb6 100644
--- a/macros/latex/contrib/acrotex/exerquiz.dtx
+++ b/macros/latex/contrib/acrotex/exerquiz.dtx
@@ -22,7 +22,7 @@
%<randomize>\ProvidesFile{aebrandom.def}
%<sumrytbls>\ProvidesFile{aebsumrytbls.def}
%<template>\ProvidesFile{template.def}
-%<package|driver|aebjs|eqexam|randomize|sumrytbls|template> [2021/04/24 v8.7 %
+%<package|driver|aebjs|eqexam|randomize|sumrytbls|template> [2021/05/10 v8.7.7 %
%<package> Exerquiz: Exercises and Quizzes for LaTeX/PDF package (dps)]
%<driver> Exerquiz documentation driver file (dps)]
%<aebjs> Exerquiz document level JavaScript (dps)]
@@ -73,6 +73,7 @@
\begin{document}
\let\env\texttt\let\pkg\textsf
\let\app\textsf
+ \let\tops\texorpdfstring
\GetFileInfo{exerquiz.sty}
\title{Exerquiz: Exercises and Quizzes for \LaTeX/PDF}
\author{D. P. Story\\
@@ -271,17 +272,23 @@
% \leavevmode\IndexOpt{nodljs}^^A
% An option for excluding all DLJS from the document. Useful with the
% \texttt{forpaper} option, or a document destined to be printed. Pass
-% on to insdljs package.
+% on to \pkg{insdljs} package.
% \begin{macrocode}
\DeclareOption{nodljs}{\PassOptionsToPackage{nodljs}{insdljs}%
\AtEndOfPackage{\let\importdljs\eq@YES}}
% \end{macrocode}
% \leavevmode\IndexOpt{execAfter}^^A
-% Execute any JS defined within the \texttt{execJS} environment. Works only for
+% Execute any JS defined within the \env{execJS} environment. Works only for
% authors using Acrobat 5.0 or Acrobat Approval.
% \begin{macrocode}
\DeclareOption{execJS}{\PassOptionsToPackage{execJS}{insdljs}}
% \end{macrocode}
+% \leavevmode\IndexOpt{usealtadobe}^^A
+% Pass the \opt{usealtadobe} to \pkg{insdljs} as a convenience option.
+% \changes{v8.7.7}{2021/05/10}{Pass \string\opt{usealtadobe} option to \string\pkg{insdljs}}
+% \begin{macrocode}
+\DeclareOption{usealtadobe}{\PassOptionsToPackage{usealtadobe}{insdljs}}
+% \end{macrocode}
% \leavevmode\IndexOpt{exercisesonly}^^A
% If the document author wants only to create a series of exercises, no quizzes, there is no
% need for the Document-level JavaScript. So, we have a couple of convenience options.
@@ -841,7 +848,12 @@
\RequirePackage{verbatim}
\RequirePackage{hyperref}
\RequirePackage{amssymb}% used for return symbols
-\RequirePackage{eforms}[2019/10/23]
+% \end{macrocode}
+% (2021/05/10) Newer version of \pkg{eforms} required, as this package uses
+% \cs{dl@EForAF4}, which is defined by \pkg{insdljs} of the same date.
+% \changes{v8.7.7}{2021/05/10}{Now require \string\pkg{eforms} dated 2021/05/10}
+% \begin{macrocode}
+\RequirePackage{eforms}[2021/05/10]
\dlSetPkgInfo
% \end{macrocode}
% \begin{macrocode}
@@ -856,7 +868,7 @@
}{}
% \end{macrocode}
% \begin{macrocode}
-\edef\eq@restoreCats{% dps17
+\edef\eq@restoreCats{%
\catcode`\noexpand\"=\the\catcode`\"\relax
\catcode`\noexpand\'=\the\catcode`\'\relax
\catcode`\noexpand\,=\the\catcode`\,\relax
@@ -4041,6 +4053,7 @@
\AA{\AAFormat{%
if\eqSP(typeof\eqSP\oField=="undefined")\eqSP
var\eqSP\oField=new\eqSP Object;\r
+ \oField.sqTlyTotCnt=0;\r
\oField.Grp={};%
\ifx\defaultColorJSLoc\@empty\else\r
\oField.DefaultColorJSLoc=\defaultColorJSLoc;\fi
@@ -5953,7 +5966,7 @@ if (isEndQuizPushed("@eqBaseName")){
%<*package|eqexam>
\def\Ans{\Ans@list}%
}% list
-}{\endlist\setcounter{quizno}{0}\eq@answersEndHook}
+}{\eq@answersEndHook\endlist\setcounter{quizno}{0}}
% \end{macrocode}
% Answers environment for a tabular environment. This command picks
% up the arguments of \cs{Ans}, then passes on the \cs{@Ans}
@@ -6043,10 +6056,12 @@ if (isEndQuizPushed("@eqBaseName")){
% \end{macrocode}
%
% \begin{macro}{\endanswers}
-% Close off \texttt{tabular} environment, and reinitialize the
+% Close off \texttt{tabular} environment, and re-initialize the
% \texttt{quizno} counter. Added \cs{answersEndHook}.
% \begin{macrocode}
-\newcommand\answersEndHook[1]{\def\eq@answersEndHook{#1}}
+\newcommand\answersEndHook[1]{\def\eq@answersEndHook{#1}%
+ \ifx\eq@answersEndHook\@empty\else
+ \def\insertEndHookHere{#1}\fi}
\let\eq@answersEndHook\@empty
\def\endanswers@sq{\endtabular\setcounter{quizno}{0}%
\eq@answersEndHook\reset@doendpe{\the\everypar}%
@@ -6183,11 +6198,19 @@ var qzSolnDest="*@qzsolndest";
var solnAfter=*ifeq@solutionsafter%
true*else%
false*fi;
-if ((qzSolnDest!="") && !solnAfter) %
-jmpToNamedDest("*oField","*@qzsolndest",%
-*ifx*@sqTurnOffAlerts*eq@Zero0*else1*fi);%
-*ifx*eqAddAAMouseUpMC*empty*else
-*eqAddAAMouseUpMC*fi
+% \end{macrocode}
+% Introduce changes in this code in response to \cs{sqSolnBtn} command.
+% \changes{v8.7.5}{2021/05/05}{\string\cs{sqSolnBtn} changes: execute block
+% if \string\cs{sqSolnBtn} not detected}
+% \begin{macrocode}
+var f=this.getField("corr.*oField.*thequestionno");
+if (f==null) {
+ if ((qzSolnDest!="") && !solnAfter) %
+ jmpToNamedDest("*oField","*@qzsolndest",%
+ *ifx*@sqTurnOffAlerts*eq@Zero0*else1*fi);%
+ *ifx*eqAddAAMouseUpMC*empty*else
+ *eqAddAAMouseUpMC*fi
+}
\end{defineJS}
% \end{macrocode}
% JavaScript code for the mouse up action for the \emph{incorrect} choice of the radio button field
@@ -6337,23 +6360,31 @@ for (var i=0; i<a.length; i++)
if ( (a[i].isBoxChecked(0)) && %
(a[i].value.charAt(0)==0) )
a[i].checkThisBox(0,false);%
-*ifx*@sqTurnOffAlerts*eq@One%
-OnBlurRespBox(true,"*oField");
+*ifx*@sqTurnOffAlerts*eq@One
+OnBlurRespBox(true,"*oField");*else
*fi%
var qzSolnDest="*@qzsolndest";
var solnAfter=*ifeq@solutionsafter%
true*else%
false*fi;
-if ( (qzSolnDest != "") && !solnAfter ) {
- for (var i=0; i<a.length; i++){
- if ((a[i].exportValues[0].charAt(0)==1) && %
+% \end{macrocode}
+% Introduce changes in this code in response to \cs{sqSolnBtn} command.
+% \changes{v8.7.5}{2021/05/05}{\string\cs{sqSolnBtn} changes: execute block
+% if \string\cs{sqSolnBtn} not detected}
+% \begin{macrocode}
+var f=this.getField("corr.*oField.*thequestionno");
+if (f==null) {
+ if ( (qzSolnDest != "") && !solnAfter ) {
+ for (var i=0; i<a.length; i++){
+ if ((a[i].exportValues[0].charAt(0)==1) && %
(!a[i].isBoxChecked(0))) break;
+ }
}
+ if (i>=a.length) jmpToNamedDest("*oField","*@qzsolndest",%
+ *ifx*@sqTurnOffAlerts*eq@Zero0*else1*fi);%
+ *ifx*eqAddAAMouseUpMS*empty*else
+ *eqAddAAMouseUpMS*fi
}
-if (i>=a.length) jmpToNamedDest("*oField","*@qzsolndest",%
-*ifx*@sqTurnOffAlerts*eq@Zero0*else1*fi);%
-*ifx*eqAddAAMouseUpMS*empty*else
-*eqAddAAMouseUpMS*fi
\end{defineJS}
% \end{macrocode}
% Mouse up action for a \emph{incorrect answer box} (a checkbox) to MS question of short-quiz
@@ -6369,9 +6400,8 @@ for (var i=0; i<a.length; i++) {
a[i].checkThisBox(0,false);
}
}%
-*ifx*@sqTurnOffAlerts*eq@One%
-OnBlurRespBox(false,"*oField");
-*fi%
+*ifx*@sqTurnOffAlerts*eq@One
+OnBlurRespBox(false,"*oField");*fi%
*ifx*oField*@empty*else
updateTally("*oField.*thequestionno");*fi%
*ifx*eqAddAAMouseUpMS*empty*else
@@ -6547,8 +6577,7 @@ updateTally("*oField.*thequestionno");*fi%
\setlength{\labelsep}{0pt}%
\def\Ans{\Ans@list}%
}%
-}{\endlist\setcounter{quizno}{0}%
- \eq@answersEndHook
+}{\eq@answersEndHook\endlist\setcounter{quizno}{0}%
\setdefault@Ans
\ifx\aeb@answerType\aeb@answerType@r
% \end{macrocode}
@@ -7826,6 +7855,11 @@ updateTally("*oField.*thequestionno");*fi%
\global\let\aebtitleQuiz\@empty
\global\let\aebTitleQuiz\@empty
\global\let\eq@tq@star\relax
+% \end{macrocode}
+% (2021/05/07) Reset \cs{eqpriorhook} at end of \env{oQuestions} environment.
+% \changes{v8.7.6}{2021/05/07}{Reset \string\cs{eqpriorhook} at end of \string\env{oQuestions} environment}
+% \begin{macrocode}
+ \global\let\oqpriorhook\@empty
\aftergroup\ignorespaces
}
\def\oSolution#1{\edef\@qzsolndest{#1}}
@@ -9055,51 +9089,109 @@ if(event.willCommit) {
}
% \end{macrocode}
% \end{macro}
-%\subsection{Fields that Support the Fill-Ins}
-% \begin{macro}{\sqTallyBox}
+% \section{Fields that play a supportive role}
+%
+% \subsection{Support for the short-quiz}
+%
+% \subsubsection{The \tops{\protect\cs}{\textbackslash}{sqTallyBox} command}
+%
+% \begin{macro}{\sqTallyBox}\hskip-\marginparsep\texttt{[\ameta{options}]}
% The \cmd{\sqTallyBox} holds the number of incorrect responses to the
-% question. This box is not required to appear. If it does not
-% appear, use \cmd{\RespBoxNT} to prevent the doc level JavaScript
-% from trying to write a nonexistent text field.
+% question. This box is not required to appear.
% \begin{macrocode}
\let\@@sqTallyBoxActions\@empty
-\@ifundefined{calcOrder}{%
-\ifpdf\def\@@sqTallyBoxActions{%
- \AA{\AAValidate{getTotalTally("\oField");}}}\fi}{}
+%\@ifundefined{calcOrder}{%
+%\ifpdf\def\@@sqTallyBoxActions{%
+% \AA{\AAValidate{getTotalTally("\oField");}}}\fi}{}
+%\ifpdf\def\@@sqTallyBoxActions{%
+% \AA{\AAValidate{getTotalTally("\oField");}}}\else
+% \let\@@sqTallyBoxActions\@empty\fi
\def\sqTallyBoxDefaults{%
- \BC{0 0 0}\W{1}\textColor{1 0 0 rg}\S{I}\Q{2}\Ff{\FfReadOnly}
-}
-\ifpdf\def\@@sqTallyBoxActions{%
- \AA{\AAValidate{getTotalTally("\oField");}}}\else
- \let\@@sqTallyBoxActions\@empty
-\fi
+ \BC{0 0 0}\W{1}\textColor{1 0 0 rg}\S{I}\Q{2}\Ff{\FfReadOnly}}
\newcommand\sqTallyBox[1][]{%
\mbox{\text@@Field{#1}{tally.\oField.\thequestionno}%
{\TBW}{\DefaultHeightOfWidget}%
{}{\eq@setWidgetProps\eq@TextField}%
{\sqTallyBoxDefaults\@@sqTallyBoxActions\every@eqTextField
- \every@sqTallyBox}}%
-}
+ \every@sqTallyBox}}}
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\sqTallyTotal}
+% \subsubsection{The \tops{\protect\cs}{\textbackslash}{sqTallyTotal} command}
+% \begin{macro}{\sqTallyTotal}\hskip-\marginparsep\texttt{[\ameta{options}]}
% This text field stores the tally total. Only used within the
% \texttt{shortquiz} environment. Takes on optional parameter; this
-% parameter can be used to modify the appearance of the fields.
+% parameter can be used to modify the appearance of the fields. Two special
+% key-values are also recognized: \cs{weakpass\darg{\ameta{n}}} and \cs{strongpass\darg{\ameta{n}}}
% \begin{macrocode}
\def\sqTallyTotalDefaults{%
- \rawPDF{}\W{1}\BC{0 0 0}\S{I}\textColor{1 0 0 rg}%
- \Q{2}\Ff{\FfReadOnly}%
-}
-\def\@@sqTallyTotalActions{%
- \AA{%
- \AAKeystroke{AFNumber_Keystroke(0,0,0,0,"",true);}
- \AAFormat{AFNumber_Format(0,0,0,0,"",true);}
- \AACalculate{%
- AFSimple_Calculate("SUM",new Array("tally.\oField"));
- }}%
+ \rawPDF{}\W{1}\BC{0 0 0}\S{I}\textColor{1 0 0 rg}
+ \Q{2}\Ff{\FfReadOnly}
}
+% \end{macrocode}
+% \DescribeMacro{\sqWeakMsg} The message that appears in an alert box
+% when the use has exceeded the weak-pass limit.
+% \begin{macrocode}
+\flJSStr{\sqWeakMsg}{You have missed too many questions.
+After you finish, it is recommended you retake this quiz
+with fewer errors and greater understanding.}
+% \end{macrocode}
+% \DescribeMacro{\sqStrongMsg} The message that appears in an alert box
+% when the use has exceeded the strong-pass limit.
+% \begin{macrocode}
+\flJSStr{\sqStrongMsg}{You have missed too many questions.
+We are resetting the quiz. Start over, this time with
+fewer errors and greater understanding.}
+% \end{macrocode}
+% The code that formats the field and if needed, responds to the weak-pass
+% or strong-pass parameter.
+% \begin{macrocode}
+\def\@@sqTallyTotalActions{\AA{%
+ \AAKeystroke{\dl@EForAF4Number_Keystroke(0,0,0,0,"",true);}
+ \AAFormat{\dl@EForAF4Number_Format(0,0,0,0,"",true);}
+ \AACalculate{%
+ \dl@EForAF4Simple_Calculate("SUM",new Array("tally.\oField"));\r
+ var sqTlyTotl=event.value;
+ \ifx\eq@strongpass\@empty
+ \ifx\eq@weakpass\@empty\else\r
+% \end{macrocode}
+% \textbf{Weak pass:} When \uif{sqTlyTotl} exceeds \cs{eq@weakpass},
+% an alert message with a message of \cs{sqWeakMsg}.
+% \begin{macrocode}
+ if(sqTlyTotl > \eq@weakpass) {\r\t
+ if (\oField.sqTlyTotCnt==0)\r\t\t
+ app.alert(\sqWeakMsg);\r\t
+ \oField.sqTlyTotCnt++;\r
+ }
+ \fi
+ \else\r
+% \end{macrocode}
+% \textbf{Strong pass:} When \uif{sqTlyTotl} exceeds \cs{eq@strongpass},
+% an alert message with a message of \cs{sqStrongMsg}, and the whole
+% short-quiz is reset.
+% \begin{macrocode}
+ if(sqTlyTotl > \eq@strongpass) {\r\t
+ app.alert(\sqStrongMsg);\r
+ \@@sqClearButtonJSCode\r
+ event.value=0;\r
+ }
+ \fi
+}}}
+% \end{macrocode}
+% \begin{macrocode}
+\def\@eqweakpass#1{\def\eq@weakpass{#1}}
+\def\@eqstrongpass#1{\def\eq@strongpass{#1}}
+\let\eq@weakpass\@empty
+\let\eq@strongpass\@empty
+% \end{macrocode}
+% On 2021/05/07, the action of \cs{sqTallyTotal} is enhanced; two special keys-values
+% are defined: \cs{weakpass\darg{\ameta{n}}} and \cs{strongpass\darg{\ameta{n}}}.
+% For the weak pass, as soon as the student misses more than \ameta{n} questions,
+% an alert box message; for the strong pass, an alert message appears and the quiz
+% is reset.
+% \changes{v8.7.6}{2021/05/07}{Enhanced capabilities of \string\cs{sqTallyTotal}}
+% \begin{macrocode}
\newcommand\sqTallyTotal[1][]{%
+ \processAppArgs#1\end\@nil
\mbox{\text@@Field{#1}{tallytotal.\oField}{\TBW}%
{\DefaultHeightOfWidget}{\eq@protect\AA}%
{\eq@setWidgetProps\eq@TextField}%
@@ -9108,6 +9200,160 @@ if(event.willCommit) {
}
% \end{macrocode}
% \end{macro}
+%
+% \subsubsection{The \tops{\protect\cs}{\textbackslash}{sqClearButton} command}
+%
+% \begin{macro}{\sqClearButton}
+% This button will clear the tallyfields and change the color of
+% the \cmd{\RespBox} back to \cmd{\defaultColorJS}. The button clears the fields
+% based on the current value of \cmd{\oField}. This text macro is
+% given its value when the optional parameter in the
+% \texttt{shortquiz} environment is specified.
+%\changes{v6.3g}{2008/10/13}
+%{%
+% Fixed a problem with the clear button not setting the boundary color
+% back to the default. I must have changed the name of an objective field,
+% now, we say \string\texttt{this.getField("obj.\string\cs{oField}")}.
+%}
+% \begin{macrocode}
+\def\sqClearButtonDefaults
+{%
+ \CA{\eq@local@sqClearButton}\textColor{0 g}\F{\FPrint}
+ \BC{0 0 0}\BG{.7529 .7529 .7529}\W{1}\S{B}\Ff{\FfNoExport}
+}
+% \end{macrocode}
+% In an attempt to supply some custom colors for the shortquiz, we
+% define \cmd{\sqRespBoxResetColor}. It determines the clear color
+% \changes{v8.6}{2020/11/29}{Rewrote SQ clear button using \string\env{defineJS} env}
+% \begin{macrocode}
+\begin{defineJS}[\makeesc\*\makecmt\%]{\@@sqClearButtonJSCode}
+ProcessIt = false;
+if ( typeof *oField == "undefined" )
+ *oField = new Object;
+if (typeof appAlerts["*oField"] == "undefined")
+ appAlerts["*oField"] = new Object;
+this.resetForm(new Array("mc.*oField","obj.*oField",%
+"tally.*oField","grpobj.*oField"));
+var f = this.getField("obj.*oField");
+if ( f != null ) f.strokeColor=*ifx*defaultColorJSLoc*@empty%
+*defaultColorJS*else*defaultColorJSLoc*fi;
+f = this.getField("grpobj.*oField");
+% \end{macrocode}
+% Here, we give the user an opportunity to designate the color
+% of the response boxes when they are reset by the \cs{sqClearButton}.
+% The default is to use \cs{eqDefaultColor}.
+% \begin{macrocode}
+if ( f != null ) f.strokeColor=*ifx*defaultColorJSLoc*@empty%
+*defaultColorJS*else*defaultColorJSLoc*fi;
+f = this.getField("rbmarkup.*oField");
+if ( f != null ) f.display=display.hidden;
+*oField.Grp = {};
+appAlerts["*oField"].bAfterValue=false;
+% \end{macrocode}
+% \begin{macrocode}
+*oField.sqTlyTotCnt=0;
+ProcessIt=true;
+\end{defineJS}
+\def\@@sqClearButtonActions{\A{\JS{\@@sqClearButtonJSCode}}}
+\newcommand\sqClearButton[1][]{%
+ \mbox{\push@@Button{#1}{clear.\oField}{}{\DefaultHeightOfWidget}%
+ {\eq@protect\A}{\eq@setButtonProps\eq@Button@driver}%
+ {\sqClearButtonDefaults\@@sqClearButtonActions\every@ButtonField
+ \every@sqClearButton}}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{The \tops{\protect\cs}{\textbackslash}{sqSolnBtn} command}
+% The default scheme for pointing the student to the soltuion to a MC or MS question
+% is through the buttons themselves. For MC, when the student chooses the correct
+% answer from the choice field, the page jumps to the soltution page automatically
+% (assuming there is a solution); for MS, the same jump does not occur until all
+% correct choices are made.
+%
+% In this section, we introduce an alternate scheme for handling jumps to MC and
+% MS questions.
+% \changes{v8.7.5}{2021/05/05}{Defined \string\cs{sqSolnBtn}}
+% \par\medskip\noindent
+% \DescribeMacro{\sqSolnMCMsg} Alert message for MC question
+% \begin{macrocode}
+\flJSStr{\sqSolnMCMsg}{You must first select the correct
+answer to see the solution.}
+% \end{macrocode}
+% \DescribeMacro{\sqSolnMSMsg} Alert message for MS question
+% \begin{macrocode}
+\flJSStr{\sqSolnMSMsg}{You must first select all the correct
+answers to see the solution.}
+% \end{macrocode}
+% \DescribeMacro{\sqCorrSolCodeMC} The code for \cs{sqSolnBtn} when the choice
+% field is MC
+% \begin{macrocode}
+\begin{defineJS}[\makeesc\*\makecmt\%]{\sqCorrSolCodeMC}
+var qzSolnDest="*@qzsolndest";
+var solnAfter=*ifeq@solutionsafter%
+true*else%
+false*fi;
+var qzSolnDest="*@qzsolndest";
+var f=this.getField("mc.*oField.*thequestionno");
+if(f.value.charAt(0)=="1") {
+ if ((qzSolnDest!="") && !solnAfter) %
+jmpToNamedDest("answer",qzSolnDest,1);
+} else app.alert(*sqSolnMCMsg);
+\end{defineJS}
+% \end{macrocode}
+% \DescribeMacro{\sqCorrSolCodeMS} The code for \cs{sqSolnBtn} when the choice
+% field is MS
+% \begin{macrocode}
+\begin{defineJS}[\makeesc\*\makecmt\%]{\sqCorrSolCodeMS}
+// multiple selection
+var g=this.getField("mc.*oField.*thequestionno");
+var a=g.getArray();
+var qzSolnDest="*@qzsolndest";
+var solnAfter=*ifeq@solutionsafter%
+true*else%
+false*fi;
+var qzSolnDest="*@qzsolndest";
+var f=this.getField("corr.*oField.*thequestionno");
+if ( (qzSolnDest != "") && !solnAfter ) {
+ for (var i=0; i<a.length; i++){
+ if ((a[i].exportValues[0].charAt(0)==1) && %
+(!a[i].isBoxChecked(0))) break;
+ }
+}
+if (i>=a.length) jmpToNamedDest("*oField","*@qzsolndest",%
+*ifx*@sqTurnOffAlerts*eq@Zero0*else1*fi);
+else app.alert(*sqSolnMSMsg);
+\end{defineJS}
+% \end{macrocode}
+% The action for \cs{sqSolnBtn} as a function of whether
+% this is a MC or MS button.
+% \begin{macrocode}
+\def\sqCorrSolButtonActionHook{\ifx\aeb@answerType
+ \aeb@answerType@r\JS{\sqCorrSolCodeMC}\else
+ \JS{\sqCorrSolCodeMS}\fi
+}
+% \end{macrocode}
+% \DescribeMacro{\sqSolnBtn}\hskip-\marginparsep\texttt{[\ameta{options}]} The
+% code for \cs{sqSolnBtn}. This command is usually inserted into the workflow
+% through the \cs{answersEndHook} command.
+% \begin{macrocode}
+\newcommand{\sqSolnBtn}[1][]{%
+ \def\Fld@name{corr.\oField.\thequestionno}%
+ \edef\@@CorrSolButtonActions{\noexpand
+ \A{\noexpand\sqCorrSolButtonActionHook}}%
+% \end{macrocode}
+% The \cs{sqSolnBtn} button only appears when \cs{@qasolndest} is nonempty.
+% \begin{macrocode}
+ \ifx\@qzsolndest\@empty\else
+ \mbox{\push@@Button{#1}{\Fld@name}{}{\DefaultHeightOfWidget}%
+ {\eq@protect\A}{\eq@setButtonProps\eq@Button@driver}%
+ {\CorrAnsButtonDefaults\@@CorrSolButtonActions
+ \every@ButtonField\every@CorrAnsButton}}\fi
+}
+% \end{macrocode}
+%
+% \subsection{The \tops{\protect\cs}{\textbackslash}{CorrAnsButton} buttons}
+%
% \begin{macro}{\CorrAnsButton}
% The \cmd{\CorrAnsButton} is a button macro which, when pressed, will
% display the correct answer for the user. This button is again
@@ -9172,7 +9418,8 @@ if(event.willCommit) {
% \end{macrocode}
% \leavevmode\DescribeMacro{\sqCorrAnsCode}
% The JavaScript code for \cs{CorrAnsButton} now in a \env{defineJS} env.
-% \changes{v8.6}{2020/11/29}{code for \string\cs{CorrAnsButton} now in a \string\env{defineJS} env}
+% \changes{v8.6}{2020/11/29}{code for \string\cs{CorrAnsButton} now in a
+% \string\env{defineJS} env}
% \begin{macrocode}
\begin{defineJS}[\makeesc\!\makecmt\%]{\sqCorrAnsCode}
!ifx!@qzsolndest!@empty%
@@ -9230,63 +9477,9 @@ else !processJSfunc("obj.!oField.!thequestionno","!CorrectAns",%
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\sqClearButton}
-% This button will clear the tallyfields and change the color of
-% the \cmd{\RespBox} back to \cmd{\defaultColorJS}. The button clears the fields
-% based on the current value of \cmd{\oField}. This text macro is
-% given its value when the optional parameter in the
-% \texttt{shortquiz} environment is specified.
-%\changes{v6.3g}{2008/10/13 }
-%{%
-% Fixed a problem with the clear button not setting the boundary color
-% back to the default. I must have changed the name of an objective field,
-% now, we say \string\texttt{this.getField("obj.\string\cs{oField}")}.
-%}
-% \begin{macrocode}
-\def\sqClearButtonDefaults
-{%
- \CA{\eq@local@sqClearButton}\textColor{0 g}\F{\FPrint}
- \BC{0 0 0}\BG{.7529 .7529 .7529}\W{1}\S{B}\Ff{\FfNoExport}
-}
-% \end{macrocode}
-% In an attempt to supply some custom colors for the shortquiz, we
-% define \cmd{\sqRespBoxResetColor}. It determines the clear color
-% \changes{v8.6}{2020/11/29}{Rewrote SQ clear button using \string\env{defineJS} env}
-% \begin{macrocode}
-\begin{defineJS}[\makeesc\*\makecmt\%]{\@@sqClearButtonJSCode}
-ProcessIt = false;
-if ( typeof *oField == "undefined" )
- *oField = new Object;
-if (typeof appAlerts["*oField"] == "undefined")
- appAlerts["*oField"] = new Object;
-this.resetForm(new Array("mc.*oField","obj.*oField",%
-"tally.*oField","grpobj.*oField"));
-var f = this.getField("obj.*oField");
-if ( f != null ) f.strokeColor=*ifx*defaultColorJSLoc*@empty%
-*defaultColorJS*else*defaultColorJSLoc*fi;
-f = this.getField("grpobj.*oField");
-% \end{macrocode}
-% Here, we give the user an opportunity to designate the color
-% of the response boxes when they are reset by the \cs{sqClearButton}.
-% The default is to use \cs{eqDefaultColor}.
-% \begin{macrocode}
-if ( f != null ) f.strokeColor=*ifx*defaultColorJSLoc*@empty%
-*defaultColorJS*else*defaultColorJSLoc*fi;
-f = this.getField("rbmarkup.*oField");
-if ( f != null ) f.display=display.hidden;
-*oField.Grp = {};
-appAlerts["*oField"].bAfterValue=false;
-ProcessIt=true;
-\end{defineJS}
-\def\@@sqClearButtonActions{\A{\JS{\@@sqClearButtonJSCode}}}
-\newcommand\sqClearButton[1][]{%
- \mbox{\push@@Button{#1}{clear.\oField}{}{\DefaultHeightOfWidget}%
- {\eq@protect\A}{\eq@setButtonProps\eq@Button@driver}%
- {\sqClearButtonDefaults\@@sqClearButtonActions\every@ButtonField
- \every@sqClearButton}}%
-}
-% \end{macrocode}
-% \end{macro}
+%
+% \subsection{The \tops{\protect\cs}{\textbackslash}{@PromptButton} command}
+%
% \begin{macro}{\@PromptButton}
% The \cs{@PromptButton} is used to create a ``progressive-style'' question (for math fill-in).
% Some series of questions build on one another. You can use this button to show the solution
@@ -9332,6 +9525,7 @@ if (!isQuizInitialized("*currQuiz")) {
\end{defineJS}
\def\PromptButtonActionHook{\JS{\PromptButtonActionCode}}
% \end{macrocode}
+% \DescribeMacro{\@PromptButton}\hskip-\marginparsep\texttt{[\ameta{options}]\darg{\ameta{answer}}}
% This button takes the standard two arguments
% \begin{flushleft}
% \texttt{\#1}: Optional parameters to change the appearance of the field\\
@@ -9363,6 +9557,9 @@ if (!isQuizInitialized("*currQuiz")) {
\newcommand{\PromptButton}{\makebox[0pt][r] % assumes xcolor
{\@PromptButton[\textColor{1 0 0 rg}]{\CorrectAns}}}
% \end{macrocode}
+%
+% \subsection{The \tops{\protect\env}{}{mathGrp} environment}
+%
% \begin{environment}{mathGrp}
% An environment for enclosing a collection of math/text fill-ins that are to be grouped
% together. This grouping should not cross a begin or end of another environment, or include more
@@ -10277,7 +10474,7 @@ aCorrectAns[!currQuiz.Grp["!thequestionno"].offset],!oField);!fi
%\end{flushleft}
% Define a special value (\cs{formatInitAltApprs}) for \cs{AddAAFormat} used in initializing \cs{RespBoxMath} problems,
% where there are alternate appearances.
-% See the {Acro\!\TeX} Blog article \url{http://www.acrotex.net/blog/?p=1335} for a discussion of the use of \cs{formatInitAltApprs}.
+% See the {Acro\negthinspace\TeX} Blog article \url{http://www.acrotex.net/blog/?p=1335} for a discussion of the use of \cs{formatInitAltApprs}.
% \changes{v8.1a}{2017/09/03}{Define a special value (\string\cs{formatInitAltApprs}) for \string\cs{AddAAFormat}}
% \begin{macrocode}
\def\formatInitAltApprs{\formatInitAltApprs}
@@ -10507,7 +10704,8 @@ var ok2Continue = true;
% from the \texttt{manswer.tex} demo file. Question 1 is a multiple selection question; Question 2
% is a multiple choice question; Question 3 is a math fill-in question; and Question 4
% is a grouped question. (The \texttt{undefined} entries indicate an empty or a not used entry.)
-%\begin{verbatim}
+%\begin{Verbatim}[xleftmargin=\parindent,fontsize=\small,
+%commandchars={!()},codes={\catcode`\%=9}]
%RightWrong.toSource()
%[undefined, [0, 1, [undefined, undefined, 0, 1, 1, 0, 1]], 1, 1,
% [undefined, 1, 1, 1, 0]]
@@ -10528,7 +10726,7 @@ var ok2Continue = true;
%
%aPointType.toSource()
% [undefined, [2, "mc"], [4, "ms"], [2, "text"], [4, "math"], [4, "grp"]]
-%\end{verbatim}
+%\end{Verbatim}
% \begin{macrocode}
var ProcessIt = true;
var retn;
@@ -10762,10 +10960,7 @@ function DisplayAnswer(fieldname,theanswer)
var oQName = new Object;
var defaultColor=(typeof oQName.DefaultColorJSLoc=="undefined")%
?\defaultColorJS:oQName.DefaultColorJSLoc;
- try {
- this.getField(fieldname).value=(theanswer);
-% this.getField(fieldname).strokeColor = defaultColor;
- } catch(e) {}
+ try { this.getField(fieldname).value=(theanswer); } catch(e) {}
ProcessIt = true;
}
function EvalCorrAnsButton(fieldname,theanswer)
@@ -10955,11 +11150,8 @@ function ParseInput(UserInput)
% \end{macrocode}
% We make a rough check of the user input, if it has alpha-words of size two or greater
% that do not match up against a recognizable function, it must be an error.
-%
-% (09/07/09) Comment this out so we check for function in both cases, get same alert message
% \begin{macrocode}
-% if (typeof(Ck4Exponents) == "undefined")
- if(!Ckfuncs(UserInput)) return false;
+ if(!Ckfuncs(UserInput)) return false;
% \end{macrocode}
% Now try to insert the multiplication operator where applicable.
% \begin{macrocode}
@@ -11064,22 +11256,21 @@ function ParseInput(UserInput)
default:
ok2Continue=false;
}
-% console.println("working.."+UserInput);
}
if (!ok2Continue)
{
eqAppAlert(\eqerrBadExp,3);
return false;
- }
- else {
+ } else {
% \end{macrocode}
-%\changes{v6.06}{2007/02/23}
-%{
+%(2007/02/23) Just before we return the parsed expression, we append all built-in
+% JavaScript functions and constants with \texttt{Math.}, this is to avoid
+% having to use the \texttt{with(Math)} construct.
+%\changes{v6.06}{2007/02/23}{%
% Now, just before we return the parsed expression, we append all built-in
% JavaScript functions and constants with \string\texttt{Math.}, this is to avoid
% having to use the \string\texttt{with(Math)} construct. These changes are in support
-% of using scientific notation.
-%}
+% of using scientific notation.}
% \begin{macrocode}
UserInput=addMathObject(UserInput);
return UserInput;
@@ -11328,8 +11519,6 @@ indepVars,oComp){
% the combinatorics functions \texttt{C(x,y)} and \texttt{P(x,y)}.
% \begin{macrocode}
var reCP=/((C|P)\(.+?)(,)(.+?\))/g
-% str="P(12,4)"
-% reCP.exec(str)
UserAns=UserAns.replace(reCP,"$1@c@$4");
% \end{macrocode}
% (2012/04/13) Bruce Wagner reports a problem with the user enters an answer containing
@@ -11389,37 +11578,31 @@ function processSpecialParse(oParse,UserAns) {
if (typeof(_o)=="function") {
% \end{macrocode}
% If \texttt{oParse} is an object (it should be an array), and the first entry is a function
-% then we have: \texttt{priorParse: [myfunction, optional arguments]}. The function is
+% then we have: \texttt{priorParse:\,[myfunction, optional arguments]}. The function is
% evaluated with the args \texttt{(UserAns, optional args)}. In the code below, we remove
% the name of the function at the beginning of the array, and insert the \texttt{UserAns}
% in its place. Various syntax variations supported.
-%\begin{verbatim}
-% priorParse: nodec,
-% priorParse: [nodec,noBinFac],
-% priorParse: [nodec,noBinFac,[myFunc,arg1, arg2,..]],
-%\end{verbatim}
+%\begin{Verbatim}[xleftmargin=\parindent,fontsize=\small,
+%commandchars={!()},codes={\catcode`\%=9}]
+%priorParse: nodec,
+%priorParse: [nodec,noBinFac],
+%priorParse: [nodec,noBinFac,[myFunc,arg1, arg2,..]],
+%\end{Verbatim}
% \begin{macrocode}
-% _o=oParse.shift();
-% oParse.unshift(UserAns);
retn=_o(UserAns);
-% retn = _o.apply(null,oParse);
if (retn==null) return retn;
% \end{macrocode}
% In this case, we break out of the loop, we don't expect any more properties
% for \texttt{priorParse} or \texttt{postParse}.
% \begin{macrocode}
-% break;
} else {
% \end{macrocode}
% If \texttt{oComp.priorParse[i]} is not a function, it is required to be an array. The first
% element of the array is the function, the rest of the entries are the additional arguments
% (in addition to \texttt{UserAns}).
% \begin{macrocode}
-% f=_o.shift();
-% _o.unshift(UserAns);
-% retn=f.apply(null,_o);
- retn=_o[0].apply(null, [ UserAns ].concat(_o.slice(1)));
- if (retn==null) return null;
+ retn=_o[0].apply(null, [ UserAns ].concat(_o.slice(1)));
+ if (retn==null) return null;
}
}
} else {
@@ -11476,6 +11659,11 @@ CorrAns,userAns,comp)
% null if expression was not valid
% -1 if expression is not a number
% \begin{macrocode}
+var ckDZRe=/\b([^0-9]*)(\d*)\./g;
+function ckDZReRepl(match,a,b,offset,string){
+ if (b[0]!="0") return match;
+ else return util.printf(a+"\%d.",b);
+}
function diffCompare(_a,_c,_v,_F,_G) {
var aXY = _c.split(",");
var _V = _v.split(","); // e.g. _V[0] = "i:x"
@@ -11511,10 +11699,31 @@ function diffCompare(_a,_c,_v,_F,_G) {
% the JavaScript interpreter does not see them. The other complication is that Acro5 objects
% to having a \texttt{return} within an \texttt{eval()}, so we work around that with a
% \texttt{rtnCode}. The returns are executed outside the \texttt{eval()}.
+% \changes{v8.7.4}{2021/05/03}{Changed logic in \string\texttt{diffCompare()} function}
% \begin{macrocode}
var rtnCode = 0;
+% \end{macrocode}
+% JavaScript has problems with numbers that are not properly written.
+% If a number has a decimal point, the integer part of the decimal must be blank, a zero (0),
+% or must begin with a non-zero number. In the \texttt{String.replace()} method below,
+% the regular expression \texttt{ckDZRe} identifies leading digits, and the function
+% \texttt{ckDZReRepl} is a replacement function that implements the requirements described above.
+% The same changes is made in \texttt{reldiffCompare()} below.
+% \begin{macrocode}
+ _G=_G.replace(ckDZRe,ckDZReRepl);
eval("try {if(isNaN(_G = eval(_G))) rtnCode=-1; }"
+"catch (e) { rtnCode=1; }");
+% \end{macrocode}
+%Below is the code removed on 2021/05/01 for the above two lines. When |_G="00.00"|, for example.
+%and |ifNaN(_G = eval(_G))| is executed, a exception is thrown and \texttt{null} is returned;
+%even though the string does evaluate to a number, but JavaScript does not recognize it as such.
+%As a result, we try an alternate strategy. The same change is made in the function
+%\texttt{reldiffCompare()}, below.
+%\begin{Verbatim}[xleftmargin=\parindent,codes={\catcode`\%=9}]
+%eval("try {if(isNaN(_G = eval(_G))) rtnCode=-1; }"
+% +"catch (e) { rtnCode=1; }");
+%\end{Verbatim}
+% \begin{macrocode}
switch(rtnCode)
{
case 0: break;
@@ -11552,6 +11761,7 @@ function diffCompare(_a,_c,_v,_F,_G) {
}
% \end{macrocode}
% This function is the same as above, but returns the relative absolute error.
+% \changes{v8.7.1}{2021/05/01}{Changed logic in \string\texttt{reldiffCompare()} function}
% \begin{macrocode}
function reldiffCompare(_a,_c,_v,_F,_G) {
var aXY = _c.split(",");
@@ -11559,16 +11769,17 @@ function reldiffCompare(_a,_c,_v,_F,_G) {
var _n = aXY.length
for (var _i=0; _i < _n; _i++)
{
- if (_V[_i].charAt(0) == "r" )
- eval ("var "+_V[_i].charAt(2)+"="+aXY[_i]+";");
- else // assume type "i"
- eval ("var "+_V[_i].charAt(2)+"="+Math.ceil(aXY[_i])+";");
+ if (_V[_i].charAt(0) == "r" )
+ eval ("var "+_V[_i].charAt(2)+"="+aXY[_i]+";");
+ else // assume type "i"
+ eval ("var "+_V[_i].charAt(2)+"="+Math.ceil(aXY[_i])+";");
}
_F = eval(_F);
if ( app.viewerVersion >= 5)
{
var rtnCode = 0;
- eval("try { if(isNaN(_G = eval(_G))) rtnCode=-1; }"
+ _G=_G.replace(ckDZRe,ckDZReRepl);
+ eval("try {if(isNaN(_G = eval(_G))) rtnCode=-1; }"
+"catch (e) { rtnCode=1; }");
switch(rtnCode)
{
@@ -11636,7 +11847,6 @@ function denyForm(UserAns, regexpr) {
var msg=\defaultReqFormMsg;
UserAns = stripWhiteSpace (UserAns);
if (!ok2Continue) return null;
-% UserAns = stripOutMuli(UserAns);
UserAns = ChngAllGrpsToParens(UserAns);
if (arguments.length>2) msg=arguments[2];
if (typeof(regexpr.length)=="undefined") {
@@ -11947,9 +12157,6 @@ function checkTheSpelling(targetFieldName) {
% field. For the \texttt{spell.checkWord()} method, \app{PDF-XChange Editor} returns \texttt{undefined}.
% This (spell checking) is a AR/AA feature only.
% \begin{macrocode}
-% var fName = "obj"+thisName.substring(3);
-% var f=this.getField(fName);
-% if (f==null) fName="grpobj"+thisName.substring(3);
var f=this.getField(targetFieldName);
var value=f.value;
var valueStrip = value.replace(/\s+/g,"");
@@ -12278,7 +12485,7 @@ function DisplayQuizResults(qtfield,nPointTotal,nQuestions)
% (2021/02/17) If there is a fourth argument for this function, it should
% be either \texttt{true} or \texttt{false}; if \texttt{true}, \texttt{DisplayQuizResults()}
% does not display quiz results; the default is \texttt{false}. This feature is used in the
-% demo file \texttt{qz-pin-to-correct.tex} found on the {Acro\!\TeX} Blog.
+% demo file \texttt{qz-pin-to-correct.tex} found on the {Acro\negthinspace\TeX} Blog.
% \changes{v8.6.4}{2021/02/17}{Added conditional (\string\texttt{\_bSilent})}
% \begin{macrocode}
var _bSilent=(arguments.length > 3 ) ? arguments[3] : false;