diff options
Diffstat (limited to 'macros/latex/contrib/acrotex/exerquiz.dtx')
-rw-r--r-- | macros/latex/contrib/acrotex/exerquiz.dtx | 523 |
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; |