summaryrefslogtreecommitdiff
path: root/texmf-dist/source
diff options
context:
space:
mode:
Diffstat (limited to 'texmf-dist/source')
-rw-r--r--texmf-dist/source/latex/acrotex/exerquiz.dtx211
1 files changed, 155 insertions, 56 deletions
diff --git a/texmf-dist/source/latex/acrotex/exerquiz.dtx b/texmf-dist/source/latex/acrotex/exerquiz.dtx
index 3890683a..8dc8ce02 100644
--- a/texmf-dist/source/latex/acrotex/exerquiz.dtx
+++ b/texmf-dist/source/latex/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/05/15 v8.8 %
+%<package|driver|aebjs|eqexam|randomize|sumrytbls|template> [2021/05/29 v8.8.2 %
%<package> Exerquiz: Exercises and Quizzes for LaTeX/PDF package (dps)]
%<driver> Exerquiz documentation driver file (dps)]
%<aebjs> Exerquiz document level JavaScript (dps)]
@@ -181,6 +181,15 @@
% No solutions for quizzes (shortquiz and quiz environments).
% \begin{macrocode}
\DeclareOption{noquizsolutions}{\eq@noquizsolutionstrue\eq@nolinktrue}
+% \end{macrocode}
+% \leavevmode\IndexOpt{allowanswers}^^A
+% Only effective when \texttt{noquizsolutions} option is in force. Normally, the \uif{Correct} control
+% (\cs{CorrAnsButton}) does not appear; if \texttt{answersallowed} is also specified,
+% the \cs{CorrAnsButton} does appear.
+% \changes{v8.8.1}{2021/05/21}{Added the \string\texttt{allowanswers} key}
+% \begin{macrocode}
+\DeclareOption{allowanswers}{\eq@answersallowedtrue}
+\newif\ifeq@answersallowed \eq@answersallowedfalse
%</package>
%<*package|eqexam>
% \end{macrocode}
@@ -4179,6 +4188,7 @@ if (typeof !oField=="undefined")
% for the associated quiz. This field has \uif{Format} code (\cs{qzIDFmt}), and the \app{Reader} will
% execute this code when the page is opened. The code creates a new array \texttt{aQuizzesInDoc}, if needed,
% and adds this quiz to the list of quizzes in the doc. Refer to \cs{qzIDFmt} above.
+% \changes{v8.8.2}{2021/05/29}{Check for dupl short-quiz names}
% \begin{macrocode}
\def\qz@IDTxtField{\makebox[0pt][l]{\textField[\autoCenter{n}\BC{}\BG{}
\S{S}\textSize{0}\Ff{\FfReadOnly}
@@ -4186,7 +4196,14 @@ if (typeof !oField=="undefined")
%</package>
%<*package|eqexam>
\let\eqQuizType\relax
-\def\@@shortquiz[#1]{%\begingroup
+\def\@@shortquiz[#1]{\csarg % dps5-29
+ \ifx{SQName-#1}\relax
+ \csarg\gdef{SQName-#1}{1}\else
+ \PackageWarning{exerquiz}{%
+ The short-quiz name '#1' is already used,\MessageBreak
+ please choose a quiz name unique throughout\MessageBreak
+ this document}\csarg\gdef{SQName-#1}{0}%
+ \fi
\gdef\oField{#1}\gdef\curr@quiz{#1}\gdef\currQuiz{#1}%
\edef\tmp@Exp{\noexpand\g@addto@macro\noexpand
\ListOfSQuizNames{,#1}}\tmp@Exp
@@ -4791,9 +4808,17 @@ if (typeof !oField=="undefined")
% quizzes in the document.
% \changes{v7.8l}{2017/07/29}{Added \string\cs{ListOfQuizNames} and
% \string\cs{ListOfSQuizNames}}
+% \changes{v8.8.2}{2021/05/29}{Check for dupl quiz names}
% \begin{macrocode}
\let\ListOfQuizNames\@empty
-\def\@quiz*#1#2{%
+\def\@quiz*#1#2{\csarg % dps5-29
+ \ifx{QzName-#2}\relax
+ \csarg\gdef{QzName-#2}{1}\else
+ \PackageWarning{exerquiz}{%
+ The quiz name '#2' is already used,\MessageBreak
+ please choose a quiz name unique throughout\MessageBreak
+ this document}\csarg\gdef{QzName-#2}{0}%
+ \fi
% \end{macrocode}
% (06/08/10) The next two lines initialize the macros for registering the
% question label, i.e., \texttt{2(a)(ii)}. These two lines are repeated for
@@ -4947,37 +4972,53 @@ if (typeof !oField=="undefined")
% isSubmitted and initializeWith to the quiz object.}
%\changes{v8.6.1}{2020/12/30}{Changed the comparison method for \string\cs{priorInitQuiz} and
% \string\cs{postInitQuiz} to reflect their \string\cs{newcommand} definition.}
+%\changes{v8.8.1}{2021/05/21}{Added a gateway into \string\cs{@initQuiz}}
+% \begin{macrocode}
+\begingroup
+ \catcode`<=1 \catcode`\>=2 \@makeother\{ \@makeother\}
+ \gdef\jsLB<{>\gdef\jsRB<}>
+\endgroup
+% \end{macrocode}
+% (2021/05/21) Added a gate keeper into \uif{Begin Quiz}. Normally, all code
+% passes through, but this can be modified by redefining \DescribeMacro\BeginQuizG@te
+% \cs{BeginQuizG@te}; restore any changes with \DescribeMacro\restorBeginQuiz
+% \cs{restorBeginQuiz}.
% \begin{macrocode}
+\newcommand{\BeginQuizG@te}{if (true)}
+\def\Norm@lBeginQuiz{if (true)}
+\def\restorBeginQuiz{\let\BeginQuizG@te\Norm@lBeginQuiz}
\newcommand\@initQuiz{%
- var\eqSP\curr@quiz=new Object();\jsR
- lstOfQuizzes["\curr@quiz"]=\curr@quiz;\jsR
- \curr@quiz.oAlertCheck={bAfterValue:false};\jsR
- \curr@quiz.Grp={};%
- \ifx\defaultColorJSLoc\@empty\else\jsR
- \oField.DefaultColorJSLoc=\defaultColorJSLoc;\fi
- \ifx\rghtColorJSLoc\@empty\else\jsR
- \oField.RightColorJSLoc=\rghtColorJSLoc;\fi
- \ifx\wrngColorJSLoc\@empty\else\jsR
- \oField.WrongColorJSLoc=\wrngColorJSLoc;\fi
- \ifx\partialColorJSLoc\@empty\else\jsR
- \oField.PartialColorJSLoc=\partialColorJSLoc;\fi
- \ifx\rghtAnsSymbJSLoc\@empty\else\jsR
- \oField.RightAnsSymbJSLoc=\rghtAnsSymbJSLoc;\fi
- \ifx\wrngAnsSymbJSLoc\@empty\else\jsR
- \oField.WrongAnsSymbJSLoc=\wrngAnsSymbJSLoc;\fi
- \ifx\corrAnsSymbJSLoc\@empty\else\jsR
- \oField.CorrAnsSymbJSLoc=\corrAnsSymbJSLoc;\fi
- \ifx\eqGradeScaleLoc\@empty\else\jsR
- \oField.GradeScaleLoc=new Array(\eqGradeScaleLoc);\fi
- \ifx\eqCorrLocalChoiceFully\@empty\else\jsR
- \oField.fullyCorrectLoc=\eqCorrLocalChoiceFully;\fi
- \if$\priorInitQuiz$\else\jsR\priorInitQuiz\fi\jsR
- InitializeQuiz("\curr@quiz",\ifnocorrections0\else1\fi);%
- \ifx\eq@CGI\@empty\jsR\curr@quiz.isSubmitted=false;\else
- \jsR\curr@quiz.isSubmitted=true;\fi
- \jsR\curr@quiz.initializeWith=%
- 'InitializeQuiz("\curr@quiz",\ifnocorrections0\else1\fi);';%
- \if$\postInitQuiz$\else\jsR\postInitQuiz\fi%
+ \BeginQuizG@te\space\jsLB\jsR\jsT
+ var\eqSP\curr@quiz=new Object();\jsR\jsT
+ lstOfQuizzes["\curr@quiz"]=\curr@quiz;\jsR\jsT
+ \curr@quiz.oAlertCheck={bAfterValue:false};\jsR\jsT
+ \curr@quiz.Grp={};%
+ \ifx\defaultColorJSLoc\@empty\else\jsR\jsT
+ \oField.DefaultColorJSLoc=\defaultColorJSLoc;\fi
+ \ifx\rghtColorJSLoc\@empty\else\jsR\jsT
+ \oField.RightColorJSLoc=\rghtColorJSLoc;\fi
+ \ifx\wrngColorJSLoc\@empty\else\jsR\jsT
+ \oField.WrongColorJSLoc=\wrngColorJSLoc;\fi
+ \ifx\partialColorJSLoc\@empty\else\jsR\jsT
+ \oField.PartialColorJSLoc=\partialColorJSLoc;\fi
+ \ifx\rghtAnsSymbJSLoc\@empty\else\jsR\jsT
+ \oField.RightAnsSymbJSLoc=\rghtAnsSymbJSLoc;\fi
+ \ifx\wrngAnsSymbJSLoc\@empty\else\jsR\jsT
+ \oField.WrongAnsSymbJSLoc=\wrngAnsSymbJSLoc;\fi
+ \ifx\corrAnsSymbJSLoc\@empty\else\jsR\jsT
+ \oField.CorrAnsSymbJSLoc=\corrAnsSymbJSLoc;\fi
+ \ifx\eqGradeScaleLoc\@empty\else\jsR\jsT
+ \oField.GradeScaleLoc=new Array(\eqGradeScaleLoc);\fi
+ \ifx\eqCorrLocalChoiceFully\@empty\else\jsR\jsT
+ \oField.fullyCorrectLoc=\eqCorrLocalChoiceFully;\fi
+ \if$\priorInitQuiz$\else\jsR\jsT\priorInitQuiz\fi\jsR\jsT
+ InitializeQuiz("\curr@quiz",\ifnocorrections0\else1\fi);%
+ \ifx\eq@CGI\@empty\jsR\jsT\curr@quiz.isSubmitted=false;\else
+ \jsR\jsT\curr@quiz.isSubmitted=true;\fi
+ \jsR\jsT\curr@quiz.initializeWith=%
+ 'InitializeQuiz("\curr@quiz",\ifnocorrections0\else1\fi);';%
+ \if$\postInitQuiz$\else\jsR\jsT\postInitQuiz\fi\jsR
+ \jsRB
}
% \end{macrocode}
% The following is the \env{defineJS} version of \cs{@initQuiz}. This is experiemental
@@ -5103,40 +5144,65 @@ if (typeof !oField=="undefined")
\every@ButtonField\every@BeginQuizButton}}}
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\eq@EndQuizButton}
-% The `End Quiz' code
+% \DescribeMacro\EndQuizG@te is an entry point in the \uif{End Quiz} action
+% that, if redefined, allows the document author to intercept the end of the quiz
+% code and insert alternate code lines; perhaps giving the student one last chance
+% to change his/her quiz before submittal. A document author may redefine \cs{EndQuizLastChance}
+% for one quiz, then change the \cs{eQzBtnActns} code by back to its default by expanding
+% \DescribeMacro\restoreEndQuiz\cs{restoreEndQuiz} after the quiz. See the DTX of the
+% package \pkg{eq-pin2corr} for an example of redefining \cs{EndQuizLastChance}.
+% The default definition is to ``pass-thru'' with no action.
+% \changes{v8.8.1}{2021/05/21}{\string\cs{EndQuizG@te} defined as part
+% of \string\cs{eQzBtnActns}}
+% \begin{macrocode}
+\newcommand{\EndQuizG@te}{if (true)}
+\def\Norm@lEndQuiz{if (true)}
+\def\restoreEndQuiz{\let\EndQuizG@te\Norm@lEndQuiz}
+% \end{macrocode}
+% \begin{macro}{\eQzBtnActns}
+% The `End Quiz' JavaScript action code
+% \changes{v8.8.1}{2021/05/21}{Modified \string\cs{eQzBtnActns} to allow more
+% customizations by inserting \string\cs{EndQuizLastChance} into the code}
% \begin{macrocode}
\begin{defineJS}[\makeesc\*\makecmt\%]{\eQzBtnActns}
if (!isQuizInitialized("*curr@quiz"))
eqAppAlert(InitMsg("*bqlabelISO"),3);
else {
if (*minQuizResp(*thequestionno)&&_ModalNotOn){
- *curr@quiz.PtValues=new Array(*pointValuesArray);
- ProbType=[*ptypeArray];%
+% \end{macrocode}
+% Insert one last chance.
+% \begin{macrocode}
+ *EndQuizG@te {
+ *curr@quiz.PtValues=new Array(*pointValuesArray);
+ ProbType=[*ptypeArray];%
*if@inclkey
- *curr@quiz.CorrAns=new Array(*corrAnsArray);*fi
+ *curr@quiz.CorrAns=new Array(*corrAnsArray);*fi
% \end{macrocode}
% (2021/02/17) Pass a fourth argument to \texttt{DisplayQuizResults()}, its default
% value is \texttt{bDisplaySilent=false}, but can be changed locally
% to \texttt{true}. When \texttt{bDisplaySilent=true}, \texttt{DisplayQuizResults()}
-% does not write its results to any field (Score Field, Points Field, etc.).
+% does not write its results to any field (\uif{Score Field}, \uif{Points Field}, etc.).
% \changes{v8.6.4}{2021/02/17}{We pass
% a new \texttt{bDisplaySilent} argument to \texttt{DisplayQuizResults} for ``silent reporting''}
% \begin{macrocode}
- DisplayQuizResults("*curr@quiz",*theeqpointvalue,%
+ DisplayQuizResults("*curr@quiz",*theeqpointvalue,%
*thequestionno,bDisplaySilent);
- bDisplaySilent=false;
- var h=this.getField("ScoreData.*curr@quiz");
- h.value=Score+";"+NQuestions+";"%
+ bDisplaySilent=false;
+ var h=this.getField("ScoreData.*curr@quiz");
+ h.value=Score+";"+NQuestions+";"%
+ptScore+";"+NPointTotal;%
*ifx*eq@submitURL*empty*else
- *eq@submitURL*fi%
+ *eq@submitURL*fi%
*if$*postSubmitQuiz$*else
- *postSubmitQuiz*fi
- resetQuiz("*curr@quiz");
+ *postSubmitQuiz*fi
+ resetQuiz("*curr@quiz");
+ }
}
}
\end{defineJS}
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
\def\EndQuizButtonDefaults{%
\CA{\eqlabel}\F{\FPrint}\BC{1 0 0}
\BG{.7529 .7529 .7529}\W{1}\S{B}\H{P}}
@@ -5144,6 +5210,9 @@ else {
\A{\JS{\eQzBtnActns}}}
\newcommand{\eq@hiddenScoreData}{\makebox[0pt][r]{%
\textField[\BC{}\F{\FHidden}]{ScoreData.\curr@quiz}{2bp}{2bp}}}
+% \end{macrocode}
+% \begin{macro}{\eq@EndQuizButton}
+% \begin{macrocode}
\newcommand\eq@EndQuizButton[1][]{%
\ifx\eq@CGI\@empty
\let\eq@submitURL\@empty
@@ -7998,9 +8067,17 @@ updateTally("*oField.*thequestionno");*fi%
% of this question. This name is used to define the macro \cmd{\oField} which is used
% by support macros. The \texttt{shortquiz} environment can also be used for
% single/multiple questions as well.
+% \changes{v8.8.2}{2021/05/29}{Check for dupl oQuestion names}
% \begin{macrocode}
\let\oqpriorhook\@empty
-\newenvironment{oQuestion}[1]{%
+\newenvironment{oQuestion}[1]{\csarg % dps5-29
+ \ifx{oQName-#1}\relax
+ \csarg\gdef{oQName-#1}{1}\else
+ \PackageWarning{exerquiz}{%
+ The quiz name '#1' is already used,\MessageBreak
+ please choose a quiz name unique throughout\MessageBreak
+ this document}\csarg\gdef{oQName-#1}{0}%
+ \fi
% \end{macrocode}
% (06/08/10) The next two lines initialize the macros for registering the
% question label, i.e., \texttt{2(a)(ii)}. These two lines are repeated for
@@ -9606,7 +9683,7 @@ else !processJSfunc("obj.!oField.!thequestionno","!CorrectAns",%
\def\eq@@@CorrAnsButton#1#2#3{\gdef\CorrectAns{#2}%
\def\processJSfunc{#3}\ifx\@qzsolndest\@empty\let\JST\@empty\else
\let\JST\jsT\fi % dps17
- \ifx\eq@ProcRespIntervals\g@processJSfunc % 01/11
+ \ifx\eq@ProcRespIntervals\g@processJSfunc
\let\@inmathwarn@SAVE\@inmathwarn\let\@inmathwarn\@gobble
% \end{macrocode}
% When the response function is \texttt{ProcRespIntervals}, there may be unbalanced parentheses, we'll
@@ -9621,7 +9698,15 @@ else !processJSfunc("obj.!oField.!thequestionno","!CorrectAns",%
\ifx\@qzsolndest\@empty%\noexpand\BC{\normalCABtnBC}%
\else\noexpand\BC{\solution@Color}\fi
\noexpand\A{\noexpand\qCorrAnsButtonActionHook}}%
- \ifeq@noquizsolutions\else % dps17 (\let\rpl\eq@rpl)
+% \end{macrocode}
+% (2021/05/21) Code to support the \texttt{allowanswers} option. When the options \texttt{noquizsolutions}
+% and \texttt{allowanswers} are both specified, the \cs{CorrAnsButton} is typeset.
+% Normally, when \texttt{noquizsolutions} is specified, \cs{CorrAnsButton} not typeset.
+% \begin{macrocode}
+ \let\eq@insertFld\eq@YES
+ \ifeq@noquizsolutions\let\eq@insertFld\eq@NO
+ \ifeq@answersallowed\let\eq@insertFld\eq@YES\fi\fi
+ \ifx\eq@insertFld\eq@YES
\mbox{\let\rpl\eq@rpl
\push@@Button{#1}{\Fld@name}{}{\DefaultHeightOfWidget}%
{\eq@protect\A}{\eq@setButtonProps\eq@Button@driver}%
@@ -12434,7 +12519,16 @@ function InitializeQuiz(qtfield,mark) {
if (!isQuizInitialized(qtfield)&&!isAQuizUnfinished()) return null;
neutralizeQuizzes();
ProcessIt = false;
- aQuizControl[qtfield] = 1;
+% aQuizControl[qtfield] = 1;
+% \end{macrocode}
+% (2021/05/29) Pressing \uif{Shift-Begin Quiz} will clear the quiz,
+% but not initialize for another quiz.
+% \changes{v8.8.1}{2021/05/25}{Shift-Begin Quiz clears the quiz, but does
+% not initialize the quiz.}
+% \begin{macrocode}
+ if (arguments.length>2)
+ aQuizControl[qtfield] = arguments[2]; // 0 or 1 designed for 0
+ else aQuizControl[qtfield] = (event.shift)?0:1; // dps5-25
this.resetForm(["ScoreField." + qtfield,"mc."+qtfield,
"obj."+qtfield,"mck."+qtfield,"Ans."+qtfield,
"PointsField."+qtfield,"PercentField."+qtfield,
@@ -12453,7 +12547,7 @@ function InitializeQuiz(qtfield,mark) {
% Oa.Sys already creates a readonly field for the solutions, we don't want
% to mess with that.
% \begin{macrocode}
- if (arguments.length<3) {
+ if (arguments.length<4) {
f = this.getField("obj." + qtfield);
if ( f != null ) f.readonly = false;
}
@@ -12584,12 +12678,14 @@ function GrpRight( a, nProb, qtfield )
for ( var i=1; i <= l; i++) prod *= !!a[i];
return prod;
}
-function DisplayQuizResults(qtfield,nPointTotal,nQuestions)
-{
+function DisplayQuizResults(qtfield,nPointTotal,nQuestions) {
Score = 0; ptScore = 0;
NPointTotal=nPointTotal; NQuestions=nQuestions;
- for (var i=1; i < RightWrong.length; i++)
- {
+% \end{macrocode}
+% If \texttt{RightWrong} is undefined, set length = 0 (dps5-24)
+% \begin{macrocode}
+ var l=(typeof RightWrong=="undefined")?0:RightWrong.length;
+ for (var i=1; i < l; i++) {
if ( (typeof RightWrong[i] == "object" ) && %
( RightWrong[i][0] == "grp" ) ) {
// grouped question
@@ -12853,7 +12949,8 @@ display.visible:display.hidden;
var rbmuname = a[i].name.replace(re,"rbmarkup\.");
var oRBMarkup = this.getField(rbmuname);
var bRBMU = ( oRBMarkup != null );
- if ( RightWrong[probno] == 1 ) {
+ if ( (typeof RightWrong!="undefined") && % // dps5-24
+(RightWrong[probno] == 1) ) {
a[i].strokeColor = rightColor;
if (bRBMU) {
oRBMarkup.textColor=rightColor;
@@ -12921,7 +13018,9 @@ display.visible:display.hidden;
if ( h != null ) break;
}
var g = f.getArray();
- var qpts=(ProbDist[i]==undefined) ? 0 : ProbDist[i];
+ if (typeof ProbDist == "undefined" ) var qpts=0; // dps5-24
+ else
+ var qpts=(ProbDist[i]==undefined) ? 0 : ProbDist[i];
if ( !negPointsMarkupAllowed && (qpts < 0) ) qpts=0;
g[0].value = qpts + (( qpts == 1 ) ? " \eqptLabel\space"
: " \eqptsLabel");