diff options
Diffstat (limited to 'texmf-dist/source/latex')
-rw-r--r-- | texmf-dist/source/latex/acrotex/exerquiz.dtx | 211 |
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"); |