diff options
Diffstat (limited to 'texmf-dist/source/latex/acrotex/exerquiz.dtx')
-rw-r--r-- | texmf-dist/source/latex/acrotex/exerquiz.dtx | 2025 |
1 files changed, 1382 insertions, 643 deletions
diff --git a/texmf-dist/source/latex/acrotex/exerquiz.dtx b/texmf-dist/source/latex/acrotex/exerquiz.dtx index 0cae45ef..e9412205 100644 --- a/texmf-dist/source/latex/acrotex/exerquiz.dtx +++ b/texmf-dist/source/latex/acrotex/exerquiz.dtx @@ -4,7 +4,7 @@ %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Exerquiz.sty package, %% -%% Copyright (C) 1999-2017 D. P. Story %% +%% Copyright (C) 1999-2018 D. P. Story %% %% dpstory@uakron.edu %% %% %% %% This program can redistributed and/or modified under %% @@ -22,7 +22,7 @@ %<randomize>\ProvidesFile{aebrandom.def} %<sumrytbls>\ProvidesFile{aebsumrytbls.def} %<template>\ProvidesFile{template.def} -%<package|driver|aebjs|eqexam|randomize|sumrytbls|template> [2017/03/16 v7.8g % +%<package|driver|aebjs|eqexam|randomize|sumrytbls|template> [2018/03/21 v8.2.2 % %<package> Exerquiz: Exercises and Quizzes for LaTeX/PDF package (dps)] %<driver> Exerquiz documentation driver file (dps)] %<aebjs> Exerquiz document level JavaScript (dps)] @@ -57,6 +57,7 @@ \PackageInfo{exerquiz}{aebdocfmt.def cannot be found}} \begin{document} \let\env\texttt\let\pkg\textsf + \let\app\textsf \GetFileInfo{exerquiz.sty} \title{Exerquiz: Exercises and Quizzes for \LaTeX/PDF} \author{D. P. Story\\ @@ -81,10 +82,12 @@ % \MakeShortVerb{|} % \InputIfFileExists{aebdonotindex.def}{\PackageInfo{exerquiz}{Inputting aebdonotindex.def}} % {\PackageInfo{exerquiz}{aebdonotindex.def cannot be found}} -% % \begin{macrocode} -%<*package> % \end{macrocode} +% (v8.0 dated 2017/08/08) This version introduces multi-letter variables and what I'll term `alternate appearances'. +% This is a major addition, changes are marked by \texttt{dps17} for future reference in case something goes wrong. +% \changes{v8.0}{2017/08/08}{Introduce multi-letter variables and alternate appearances. Changes +% made are marked by `\texttt{dps17}' throughout the DTX.} % \changes{v7.7k}{2016/04/18}{Minor bug fixes, improved driver recognition} % \changes{v7.7j}{2016/04/05}{Change in eforms to 2016/04/05 v2.8f} % @@ -93,12 +96,16 @@ % Introduce a number of useful options for \textsl{exerquiz}. % \subsection{Options for paper, solutions, JavaScript and preview} % \begin{macrocode} +% Begin package segment +%<*package> \usepackage{keyval} % \end{macrocode} %\changes{v6.4t}{2012/06/18}{Added ifpdf as a required package} +%\changes{v8.1a}{2017/09/03}{Added check for luatex} % \begin{macrocode} \RequirePackage{ifpdf}[2006/02/20] \RequirePackage{ifxetex}[2006/08/21] +\RequirePackage{ifluatex} \@ifundefined{exqtable}{\def\exqtable{table}}{} \IfFileExists{xcolor.sty}{% \def\eq@ColorPackage{xcolor}% @@ -144,12 +151,11 @@ % No solutions for quizzes (shortquiz and quiz environments). % \begin{macrocode} \DeclareOption{noquizsolutions}{\eq@noquizsolutionstrue\eq@nolinktrue} -% \end{macrocode} -% \IndexOpt{online} -% An \texttt{online} options. -% \begin{macrocode} %</package> %<*package|eqexam> +% \end{macrocode} +% An \IndexOpt{online}\texttt{online} options. +% \begin{macrocode} \let\eq@YES=y \let\eq@NO=n \let\eq@One=1 \let\eq@Zero=0 \def\eq@r{r}\let\eq@f=f \let\eq@l=l @@ -177,7 +183,11 @@ % \begin{macrocode} \DeclareOption{solutionsonly}{\solutionsonlytrue\answerkeytrue \therearesolutionstrue\AtEndOfPackage{\let\exerSolnsHeadnToc\relax}} +% \end{macrocode} +% \changes{v8.1k}{2018/02/04}{Added \string\cs{ifanswerkey} switch} +% \begin{macrocode} \newif\ifsolutionsonly\solutionsonlyfalse +\@ifundefined{ifanswerkey}{\newif\ifanswerkey\answerkeyfalse}{} % \end{macrocode} % \IndexOpt{contsolns} % This option requires both \textsf{web} and \textsf{exerquiz}. The package @@ -212,8 +222,8 @@ % \IndexOpt{vspacewithsolns} % This is for the \texttt{vspacewithsolns} option designed for % \textsf{eqexam}, but can be used in \textsf{exerquiz}. The switch -% \cs{ifvspacewithsolns} is defined in \textsf{eqexam}, and we olnly -% define it here is \textsf{eqexam} is not loaded. +% \cs{ifvspacewithsolns} is defined in \textsf{eqexam}, and we only +% define it here if \textsf{eqexam} is not loaded. % \changes{v6.3x}{2011/04/05}{Added \texttt{vspacewithsolns}} % \begin{macrocode} \@ifundefined{ifvspacewithsolns}{% @@ -221,6 +231,11 @@ \newif\ifvspacewithsolns\vspacewithsolnsfalse }{} % \end{macrocode} +% \changes{v8.1m}{2018/02/09}{\string\cs{ifdisplayworkarea} conditionally defined} +% \begin{macrocode} +\@ifundefined{ifdisplayworkarea}{\newif\ifdisplayworkarea + \displayworkareafalse}{} +% \end{macrocode} % \IndexOpt{nodljs} % An option for excluding all DLJS from the document. Useful with the % \texttt{forpaper} option, or a document destined to be printed. Pass @@ -304,6 +319,15 @@ \PassOptionsToPackage{pdftex}{eforms} } % \end{macrocode} +% Added a \texttt{luatex} option +%\changes{v8.1a}{2017/09/03}{Added a \string\texttt{luatex} option} +% \begin{macrocode} +\DeclareOption{luatex}{% + \def\eq@drivernum{1}\def\eq@driver{luatex}% + \PassOptionsToPackage{luatex}{\eq@ColorPackage} + \PassOptionsToPackage{luatex}{eforms} +} +% \end{macrocode} % \IndexOpt{dvipdfm}\IndexOpt{dvipdfmx}\IndexOpt{xetex} % Set the driver dependent code for the \texttt{quiz} and \texttt{quiz} % environments. @@ -543,10 +567,20 @@ %</package> %<*package|eqexam> \newif\ifeq@noforms \eq@noformsfalse -\newif\ifeq@noquizsolutions \eq@noquizsolutionsfalse % dps new -\newif\ifnocorrections \nocorrectionsfalse +\newif\ifeq@noquizsolutions \eq@noquizsolutionsfalse % changed \ifeq@nocorrections to \ifnocorrections %\newif\ifeq@nocorrections \eq@nocorrectionsfalse +\newif\ifnocorrections \nocorrectionsfalse +% \end{macrocode} +% Added \string\cs{ifeqe@flextended} to support \string\pkg{eqexam} +% \changes{v8.1h}{2018/01/03}{Added \string\cs{ifeqe@flextended} to support \string\pkg{eqexam}} +% \changes{v8.1o}{2018/02/12}{Added \string\cs{ifcont@nnot} to support \string\pkg{eqexam}} +% \begin{macrocode} +\@ifundefined{ifeqe@flextended}{\newif\ifeqe@flextended + \eqe@flextendedfalse}{} +\@ifundefined{ifcont@nnot}{\newif\ifcont@nnot \cont@nnotfalse}{} +\@ifundefined{if@eqalignfilllinestoleft}{\newif\if@eqalignfilllinestoleft + \@eqalignfilllinestoleftfalse}{} % \end{macrocode} % (4/28/11) A switch to control whether the declared vertical space % for the \texttt{solution} environment will be preserved during the \texttt{answerkey} @@ -583,7 +617,26 @@ % \begin{macrocode} \def\SolutionsAfter{\eq@solutionsaftertrue\eq@nolinktrue} \newif\ifcqSA\cqSAfalse -\def\SolutionsAtEnd{\eq@solutionsafterfalse\eq@nolinkfalse} +% \end{macrocode} +% Modified \cs{SolutionsAtEnd} (2018/02/02) to include \cs{eq@nosolutionsfalse} +% and \cs{eq@proofingfalse}. +% \changes{v8.1j}{2018/02/02}{Added \string\cs{eq@nosolutionsfalse} +% and \string\cs{eq@proofingfalse} to the +% definition of \string\cs{SolutionsAtEnd}} +% \begin{macrocode} +%\def\SolutionsAtEnd{\eq@solutionsafterfalse\eq@nolinkfalse} +%\def\SolutionsAtEnd{\eq@solutionsafterfalse\eq@nolinkfalse +% \eq@nosolutionsfalse\eq@proofingfalse\answerkeyfalse} +\def\SolutionsAtEnd{\eq@solutionsafterfalse\eq@nolinkfalse +% \end{macrocode} +% Now, if |\ifvspacewithsolns| is true, we set |\eq@nosolutionsfalse| so solutions appear +% at the end of the file; otherwise, we set |\eq@nosolutionstrue|. +% \changes{v8.1k}{2018/02/04}{Added a conditional within \string\cs{SolutionsAtEnd}} +% \changes{v8.1m}{2018/02/09}{Include \string\cs{displayworkareatrue} in definition +% of \string\cs{SolutionsAtEnd}} +% \begin{macrocode} + \displayworkareatrue\ifvspacewithsolns\eq@nosolutionsfalse\else + \eq@nosolutionstrue\fi\eq@proofingfalse\answerkeyfalse} \def\NoSpaceToWork{\let\eq@insertverticalspace\eq@NO} \def\SpaceToWork{\let\eq@insertverticalspace\eq@YES} \SpaceToWork @@ -625,17 +678,11 @@ % \end{macrocode} % \end{macro} % \end{macro} -% \begin{macro}{\saveRandomSeed} -% \begin{macro}{\inputRandomSeed} -% These two commands are used when the \texttt{allowrandomize} option is in effect, -% Until then, they do nothing. See the definition in the section \autoref{randomize}. +% These\DescribeMacro{\saveRandomSeed}\DescribeMacro{\inputRandomSeed} two commands are used when the \texttt{allowrandomize} option is in effect, +% Until then, they do nothing. See the definition in \autoref{randomize}. % \begin{macrocode} \let\saveRandomSeed\relax \let\inputRandomSeed\relax -% \end{macrocode} -% \end{macro} -% \end{macro} -% \begin{macrocode} %</package|eqexam> %<*package> % \end{macrocode} @@ -685,15 +732,17 @@ % \end{macrocode} % If web is already loaded, we use its driver. % \changes{v6.4t}{2012/06/18}{Testing for pdflatex and xetex} +% \changes{v8.1a}{2017/09/03}{Testing for luatex} % \begin{macrocode} \@ifpackageloaded{web}{% \ExecuteOptions{\eq@driver@name}% }{% + \ifluatex\ExecuteOptions{luatex}\else \ifpdf\ExecuteOptions{pdftex}\else \ifxetex\ExecuteOptions{xetex}\else \InputIfFileExists{web.cfg}{} {\@ifundefined{l@tex@@@@driver}{\ExecuteOptions{dvips}} - {\ExecuteOptions{dvipsone}}}\fi\fi + {\ExecuteOptions{dvipsone}}}\fi\fi\fi } % \end{macrocode} % \begin{macrocode} @@ -705,8 +754,14 @@ % \begin{macrocode} \RequirePackage{array} \RequirePackage{\eq@ColorPackage} -\RequirePackage{verbatim} +% \end{macrocode} +% Changed order of loading, comment package first, then verbatim package; prior to the change, anomalous +% errors, which were traced to these two packages. +% \changes{v7.8k}{2017/07/25}{Changed order of loading, comment package first, then verbatim package} +% \begin{macrocode} \RequirePackage{comment} +\RequirePackage{verbatim} +%\RequirePackage{comment} \RequirePackage{hyperref} \RequirePackage{amssymb}% used for return symbols \RequirePackage{eforms}[2012/06/20] @@ -722,6 +777,18 @@ \MessageBreak in the option list of the exerquiz package.} }{} % \end{macrocode} +% \begin{macrocode} +\edef\eq@restoreCats{% dps17 + \catcode`\noexpand\"=\the\catcode`\"\relax + \catcode`\noexpand\'=\the\catcode`\'\relax + \catcode`\noexpand\,=\the\catcode`\,\relax + \catcode`\noexpand\(=\the\catcode`\(\relax + \catcode`\noexpand\!=\the\catcode`\!\relax + \catcode`\noexpand\_=\the\catcode`\_\relax +} +\@makeother\"\@makeother\'\@makeother\,% +\@makeother\(\@makeother\!\@makeother\_ +% \end{macrocode} % Determine whether we have solutions at end. % \begin{macrocode} \@ifundefined{ifsolutionsAtEnd} @@ -844,16 +911,21 @@ \def\exSolafterDefault{#1}\resetSolnAfterToDefault} \exsolafterDefault{\textit{Solution}:} \newcommand{\renameSolnAfterTo}[1]{\def\exsolafter{#1}} -\def\recoverDisplayBelow{\vskip\belowdisplayskip} -\newcommand{\adjDisplayBelow}{\vskip-\lastskip\vskip-\baselineskip} -% \ifsolutionsAtEnd\recoverDisplayBelow\fi} -\newcommand{\adjDisplayBelowPlus}{\adjDisplayBelow\recoverDisplayBelow} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} +% \DescribeMacro{\adjDisplayBelow} is useful when expanded beneath distplays that +% have no follow-up text below them. These seems to me, in certain situations, unnecessary +% space is created. The \cs{adjDisplayBelow} attempts to remedy this. The +% \DescribeMacro{\adjDisplayBelowPlus}\cs{adjDisplayBelowPlus} is the same as +% \cs{adjDisplayBelow}, but adds \cs{recoverDisplayBelow}. The command \cs{adjDisplayBelow} +% has a |vskip-\baselineskip|, if this is too much, use \cs{adjDisplayBelowPlus}. % \begin{macrocode} +\newcommand{\adjDisplayBelow}{\vskip-\lastskip\vskip-\baselineskip} +\newcommand{\adjDisplayBelowPlus}{\adjDisplayBelow\recoverDisplayBelow} +\def\recoverDisplayBelow{\vskip\belowdisplayskip} %</package|eqexam> %<template> %<template>% Solution label for solutionafter option for exercise @@ -1175,18 +1247,17 @@ \typeout{Check: `#1' is not an acceptable option, inserting default, `check'.} %</template> +%<*package> % \end{macrocode} -% % Announce driver option % \begin{macrocode} -%<*package> -\typeout{^^Jexerquiz: * Using \eq@driver\space option *^^J} +\PackageInfo{exerquiz}{* Using \eq@driver\space option *} +%</package> +%<*package|eqexam> % \end{macrocode} % \subsection{Handles, counters and such} % Handles to write solutions to quizzes and exercises to a file. % \begin{macrocode} -%</package> -%<*package|eqexam> \ifsolutionsonly \InputIfFileExists{\jobname_xdefs.cut}{% \typeout{^^JExerquiz|Eqexam: Reading \jobname_xdefs.cut^^J}} @@ -1237,8 +1308,6 @@ % answers. We declare this length to be 0pt. The \textsf{eqexam} resets this value. % \begin{macrocode} \newlength\eqemargin \eqemargin=0pt -% \end{macrocode} -% \begin{macrocode} %</package> %<*package|eqexam> % \end{macrocode} @@ -1260,8 +1329,6 @@ \newcounter{eqquestionnoii} \newcounter{eqquestionnoiii} \newcount\@eqquestiondepth \@eqquestiondepth=0 -% \end{macrocode} -% \begin{macrocode} %</package|eqexam> %<*package> \newcounter{grpquestionno} @@ -1363,19 +1430,17 @@ %\newcommand\exrtnlabelformat{\exlabelsol\ \theeqexno} % \end{macrocode} % \end{macro} -% \begin{macro}{\exrtnlabelformat} -% This is the formatted return label (return from the solution), +% This\DescribeMacro{\exrtnlabelformatwp} is the formatted return label (return from the solution), % for an exercise with parts. % \begin{macrocode} \newcommand\exrtnlabelformatwp{$\square$} +%</package> +%<*package|eqexam> % \end{macrocode} -% \end{macro} % \begin{macro}{\aboveexskip} % \begin{macro}{\belowexskip} % Amount of skip before and after exercise environment % \begin{macrocode} -%</package> -%<*package|eqexam> \newcommand{\belowexskip}[1]{\setlength{\eq@tmplength}{#1}% \edef\eq@exerskip{\noexpand\removelastparskip \noexpand\vskip\the\eq@tmplength\relax\kern0pt}} @@ -1479,9 +1544,9 @@ % environment, this is what I should have done originally, but now its % done. The \texttt{exercise*} signals an exercise with parts. It takes % one optional parameter, the name of a counter \texttt{<ctr>} that is to -% be used. -% \begin{macro}{\exerSolnInExtFile} -% With the exercises, you have the option of including them in the main document, or putting them +% be used.\medskip +% +% \noindent With the exercises\DescribeMacro{\exerSolnInExtFile}, you have the option of including them in the main document, or putting them % in an external document. The \cs{exerSolnsInExtFile} command lets you specify an external file name. % Just use the \textit{basename}, hyperref will add the extension. If an external file is specified, all % solution links are changed to links between documents. Usage: @@ -1494,9 +1559,6 @@ \gdef\exerSolns@ReturnPath{#1}} \let\exerSolns@ExtFile\eq@NO \def\exerSolns@ReturnPath{} -% \end{macrocode} -% \end{macro} -% \begin{macrocode} %</package> %<*package|eqexam> % \end{macrocode} @@ -1705,7 +1767,7 @@ \def\declCQSolStr#1{\def\cqSStr{#1}} \declCQSolStr{Solution} % \end{macrocode} -% Aside from the words `Question' and `Solution', the way these two are formatting is determined +% Aside from the words `Question' and `Solution', the way these two are formated is determined % through \cs{declCQPre}\DescribeMacro{\declCQPre} and \cs{declCQPost}\DescribeMacro{\declCQPost}. % These declarations are seen below. The \cs{declCQPost} is more complicated in that it handles the % formatting after the copied question; in the default definition, we skip a \cs{medskip} and do a \cs{indent}. @@ -2001,7 +2063,7 @@ % elsewhere as well. %\par\medskip\noindent % The \cs{eqterminex} command is one that appears on the solution page, just after the exercise number. -% We redefine it to do our will. The convenience macro \cs{decleqterminex}\DescribeMacro{\decleqterminex} is used for that purpose. +% We redefine it to do our will. The convenience macro \DescribeMacro{\decleqterminex}\cs{decleqterminex} is used for that purpose. % We use \cs{ifterminexchanged} to track whether the default definition is changed. % \begin{macrocode} \newif\ifterminexchanged \terminexchangedfalse % dps cq @@ -2013,9 +2075,19 @@ \decleqterminex{\eqterminexDEF} % \end{macrocode} %\changes{v6.7}{2013/04/07}{Inserted another argument into \cs{eqEXt}} -% Added another argument into \cs{eqEXt}, used for filtering. -% \begin{macrocode} +% (2013/04/07) Added another argument into \cs{eqEXt}, used for filtering.\par\medskip +% \noindent +% When solutions are written to the SOL file, they are not normally in a group. +% If you execute \DescribeMacro\makeExSolnsLocalOn\cs{makeExSolnsLocalOn}, each solution +% is written in a group. Undo this with \DescribeMacro\makeExSolnsLocalOff\cs{makeExSolnsLocalOff}, +% which is the historic default. +% \changes{v8.1p}{2018/02/13}{Added grouping for exercise solutions to the SOL file} +% \begin{macrocode} +\newif\ifmakeExSlLocal \makeExSlLocalfalse +\def\makeExSolnsLocalOn{\makeExSlLocaltrue} +\def\makeExSolnsLocalOff{\makeExSlLocalfalse} \def\eqExerSolnHeaderSngl{% + \ifmakeExSlLocal\protect\begingroup^^J\fi \protect\eqEXt{\eqExtArg}{\eqFilterArg}\protect \solnItemMngt\protect\exerSolnHeader{\exsecrunhead}{ex.\the@exno}% {\exsllabelformat}\exer@solnheadhook @@ -2030,6 +2102,7 @@ % Added another argument into \cs{eqEXt}, used for filtering. % \begin{macrocode} \def\eqExerSolnHeaderList{% + \ifmakeExSlLocal\protect\begingroup^^J\fi \protect\eqEXt{\eqExtArg}{\eqFilterArg}\protect \solnItemMngt\protect\exerSolnHeader{\exsecrunhead}% {ex.\the@exno\thepartno}{\exsllabelformatwp}% @@ -2077,10 +2150,32 @@ % \end{macro} % This macro is the beginning of the \texttt{solution} environment for % exercises. -% \begin{macrocode} -\def\solnexer@woparts{\def\bLeaveVspace{x}% = no vertical space added +% \changes{v8.1g}{2017/12/27}{added \string\cs{pushEnvir} and \string\cs{popEnvir} to remove +% \string\cs{everypar} influence in \string\cs{solnexer@woparts}} +% \changes{v8.1o}{2018/02/12}{Added cond. definition for \string\cs{if@eqalignfilllinestoleft}} +% \begin{macrocode} +\let\exsolnonceonlytophook\relax +\def\solnexer@woparts{% + \ifanswerkey\ifeqe@flextended\ifcont@nnot + \ifx\solutionparshape\@empty\else % dpsj8 + \pushEnvir + \everypar{}\if@eqalignfilllinestoleft\else + \parshape=1 \leadinIndent \linewidth\fi + \popEnvir + \fi\fi\fi\fi\def\bLeaveVspace{x}% = no vertical space added + \exsolnonceonlytophook % dps27 + \global\let\exsolnonceonlytophook\relax +% \end{macrocode} +% The following lines are needed to get a better alignment +% with the bgonly key option, in \pkg{eqexam}. +% \changes{v8.1f}{2017/12/04}{Added lines to support eqexam} +% \begin{macrocode} + \@ifundefined{KV@eqefillLines@bgonly}{} + {\ifKV@eqefillLines@bgonly\ifvmode\else + \par\leavevmode\strut\fi\fi + \ifKV@eqefillLines@outlineonly\leavevmode\strut\fi}% \ifeq@ckSolnVspace - \def\eq@next{\@ifnextchar[{\solnexer@@woparts}% + \def\eq@next{\@ifnextchar[{\solnexer@@woparts}%] {\solnexer@@woparts[\null]}}\else \def\eq@next{\solnexer@@woparts[\null]}\fi % \end{macrocode} @@ -2105,34 +2200,34 @@ {\vskip0pt\penalty-50\vglue\wlVspace\eqWriteLine \advance\@tempcnta1\relax}\par\endgroup } +\let\leavevspace\relax % dpsj5 \newcommand{\vspaceFmt}[1]{% - \ifx\solutionparshape\@empty\else + \ifx\solutionparshape\@empty\else % \end{macrocode} % This must be part of the solution for a \cs{leadinitem} question. % We need to make an adjustment to the \cs{linewidth}. % \begin{macrocode} - \advance\linewidth-\leadinIndentPrtSep\fi + \advance\linewidth-\leadinIndentPrtSep\fi \ifdim\sameVspace>0pt - \let\bLeaveVspace\@empty - \def\leavevspace{% - \ifx\eq@insertverticalspace\eq@YES\par - \eqPriorVspace{#1}{\nobreak\noindent + \let\bLeaveVspace\@empty + \def\leavevspace{% + \ifx\eq@insertverticalspace\eq@YES\par\eq@quessolskip + \eqPriorVspace{#1}{\nobreak\noindent % \end{macrocode} % If \texttt{nLines} is non-empty, we'll use some spacial code % to generate the lines so it breaks across pages. % \begin{macrocode} - \ifx\soln@keys@nLines\@empty - \if@eqlinedfiller - \def\eq@lines@next{\vspaceFiller{#1}}\else - \def\eq@lines@next{\parbox[b][#1][t]{\linewidth} - {\vspaceFiller{#1}}}\fi - \else - \def\eq@lines@next{\eq@linesXPgs}% - \fi\eq@lines@next - }% - \fi - }% - \fi + \if@eqlinedfiller + \ifx\soln@keys@nLines\@empty + \def\eq@lines@next{\vspaceFiller{#1}}\else + \def\eq@lines@next{\eq@linesXPgs}\fi + \else + \def\eq@lines@next{\parbox[b][#1][t]{\linewidth} + {\vspaceFiller{#1}}}% + \fi\eq@lines@next}% + \fi + }\expandafter\leavevspace % dpsj6 + \fi } % \end{macrocode} % \changes{v6.8g}{2014/04/08}{Added key-val here for \textsf{eqexam}.} @@ -2209,20 +2304,34 @@ % then \textsf{eqexam} should leave space for writing an answer, and put solutions at the end % of the document. % \begin{macrocode} - \ifx\sameVspace\@empty\gdef\sameVspace{0pt}\fi - \ifvspacewithsolns\vspaceFmt{\sameVspace}\fi - \ifeq@nosolutions\ifeq@solutionsafter\else - \vspaceFmt{\sameVspace}\fi\fi +% dpsj5 moved to solnexer@@@woparts +% \ifx\sameVspace\@empty\gdef\sameVspace{0pt}\fi +% \ifvspacewithsolns\vspaceFmt{\sameVspace}\fi +% \ifeq@nosolutions\ifeq@solutionsafter\else +% \vspaceFmt{\sameVspace}\fi\fi \fi\fi \solnexer@@@woparts } % \end{macrocode} % \changes{v7.7q}{2016/07/22}{Added \string\cs{solnsafterSkip}} +% \changes{v8.1h}{2018/01/03}{Added \string\cs{@solnafterSkipOnce} (package use only)} % \begin{macrocode} \def\solnsafterSkip#1{\setlength{\@tempdima}{#1}% - \def\solnsafterSkipAmt{\the\@tempdima}% - \def\solutionsafterSkip{\vskip#1\relax}} + \edef\solnsafterSkipAmt{\the\@tempdima}% + \def\solutionsafterSkip{\vskip\solnsafterSkipAmt\relax}} \solnsafterSkip{\smallskipamount} +\def\@solnafterSkipOnce#1{\setlength{\@tempdima}{#1}% + \xdef\@solnafterSkipOnceAmt{\the\@tempdima}}% +\def\@@solnafterSkipOnce{\vskip\@solnafterSkipOnceAmt\relax %dpsj3 + \gdef\@solnafterSkipOnceAmt{0pt}} +\def\@solnafterSkipOnceAmt{0pt} +% \end{macrocode} +% Add separation between the question and the \texttt{solution} environment. +% \changes{v8.1d}{2017/11/13}{Added \string\cs{quessolsep} for exercises (eqexam)} +% \begin{macrocode} +\def\quessolSkip#1{\setlength{\@tempdima}{#1}% + \edef\eq@quessolskip{\noexpand\vskip\the\@tempdima\relax}} +\def\eq@quessolskip{\vskip\smallskipamount} % \end{macrocode} % The next two definitions are used for debugging the % \cs{ifkeepdeclaredvspacing} feature (\textsf{eqexam} only). @@ -2269,95 +2378,109 @@ \let\priorexsolafterTab\@empty \let\priorexsolafterSngl\@empty \def\eq@Hid{H}\def\eq@hid{h} -\def\solnexer@@@woparts{% - \global\thereissolutiontrue - \def\exerwparts@cols{0}% - \let\verbatim@out\ex@solns - \if\currhideopt\eq@Hid +\def\solutionafterExCmds#1{\def\@rgi{#1}\ifx\@rgi\@empty + \let\eqSolnExCmds\relax\else + \def\eqSolnExCmds{#1}\fi} +\let\eqSolnExCmds\relax +\def\eq@b@ddCodeSpecialDef#1{#1}% dpsj4 +\let\eq@b@ddCodeSpecial\eq@b@ddCodeSpecialDef % dpsj4 +\def\solnexer@@@woparts{\ifeq@solutionsafter\else + \expandafter\begingroup\fi %dpsj10 + \global\thereissolutiontrue + \global\let\procsoln\relax % dpsj6 + \global\let\endprocsoln\relax % dpsj6 + \def\exerwparts@cols{0}% + \let\verbatim@out\ex@solns + \if\currhideopt\eq@Hid % \end{macrocode} % (2017/02/09) Hide \cs{minVspacet@bs} for `H' option % \changes{v7.8e}{2017/02/09}{Hide \string\cs{minVspacet@bs} for `H' option} % \begin{macrocode} - \let\minVspacet@bs\@empty - \let\procsoln\eqSavedComment - \let\endprocsoln\eqSavedEndCommet - \def\eq@next{\procsoln}% + \let\minVspacet@bs\@empty + \let\procsoln\eqSavedComment + \let\endprocsoln\eqSavedEndCommet + \def\eq@next{\procsoln}% + \else + \eq@ckglobalhide + \ifeq@hidesolution + \let\procsoln\eqSavedComment + \let\endprocsoln\eqSavedEndCommet \else - \eq@ckglobalhide - \ifeq@hidesolution - \let\procsoln\eqSavedComment - \let\endprocsoln\eqSavedEndCommet - \else - \ifx\bLeaveVspace\@empty\leavevspace\fi - \ifeq@solutionsafter\else - \ifx\eq@@CommonCmd\@empty\else - \set@display@protect - \immediate\write\verbatim@out{\eq@@CommonCmd}% - \set@typeset@protect - \fi - \fi - \let\procsoln\verbatimwrite - \let\endprocsoln\endverbatimwrite - \fi - \def\eq@next{% - \ifeq@solutionsafter%\par - \removelastskip\removelastparskip - \cqSAtrue\eqCQDeclarations - \declCopyQues{\input{\cq@CutName}}% - \ifx\exsolafter\@empty +% \ifx\bLeaveVspace\@empty\leavevspace\fi % dpsj5 + \ifeq@solutionsafter\else + \ifx\eq@@CommonCmd\@empty\else + \set@display@protect + \immediate\write\verbatim@out{\eq@@CommonCmd}% + \set@typeset@protect + \fi + \fi + \let\procsoln\verbatimwrite + \let\endprocsoln\endverbatimwrite + \fi + \def\eq@next{% + \ifeq@solutionsafter + \let\procsoln\relax % dpsj6 + \let\endprocsoln\relax + \removelastskip\removelastparskip + \cqSAtrue\eqCQDeclarations + \declCopyQues{\input{\cq@CutName}}% + \ifx\exsolafter\@empty % \end{macrocode} % If we have solutions after and there is no label and no vertical % skip specified, we do nothing other than to execute \cs{eqe@setStartSolns}, % which marks the beginning of the ``solution.'' % \begin{macrocode} - \ifdim\sameVspace=0pt\eqe@setStartSolns - \else + \ifdim\sameVspace=0pt\eqe@setStartSolns + \else % \end{macrocode} % If there is vertical space specified, we do a standard skip, and mark the beginning % of the solution with \cs{eqe@setStartSolns}. % \begin{macrocode} - \solutionsafterSkip - \eqe@setStartSolns - \fi - \else\par\kern0pt - \solutionsafterSkip - \noindent\strut\eqe@setStartSolns - \fi - \parskip\eqeques@parsep - \ifx\endparts\endexercise@parts@tabular - \eq@setPrbSolnAftrIndnt - \restorejustify -% \expandafter\setTabulrSolnEnv - \fi + \solutionsafterSkip + \@@solnafterSkipOnce % dpsj3 + \eqe@setStartSolns + \fi + \else\par\kern0pt + \solutionsafterSkip + \@@solnafterSkipOnce % dpsj3 + \noindent\strut\eqe@setStartSolns + \fi + \parskip\eqeques@parsep + \ifx\endparts\endexercise@parts@tabular + \eq@setPrbSolnAftrIndnt + \restorejustify + \fi % \end{macrocode} % (2017/02/09) Added prior \cs{exsolafter} hooks. % \changes{v7.8e}{2017/02/09}{Added prior \string\cs{exsolafter} hooks} % \begin{macrocode} - \ifx\endparts\endexercise@parts@tabular\expandafter - \priorexsolafterTab\else - \ifx\endparts\endexercise@parts@list\expandafter - \priorexsolafterList\else\expandafter - \priorexsolafterSngl\fi\fi + \ifx\endparts\endexercise@parts@tabular\expandafter + \priorexsolafterTab\else + \ifx\endparts\endexercise@parts@list\expandafter + \priorexsolafterList\else\expandafter + \priorexsolafterSngl\fi\fi % \end{macrocode} % The solution after label, followed by a space. % \begin{macrocode} - \exsolafter\space\ignorespaces +% \eqSolnExCmds % dpsj8 + \exsolafter\space\ignorespaces % \end{macrocode} % We set the shape of the solutionafter. % This is empty if \cs{leadinitem} is not used. % \begin{macrocode} - \solutionparshape - \else + \solutionparshape + \else % \end{macrocode} % Write the solution header 11/03/05 % \begin{macrocode} - \eqExerSolnHeader - \global\let\eqExerSolnHeader\@empty - \global\therearesolutionstrue\expandafter\procsoln - \fi - }% - \fi -\eq@next} + \eqExerSolnHeader + \global\let\eqExerSolnHeader\@empty + \global\therearesolutionstrue\expandafter\procsoln + \fi + }% + \fi + \eq@b@ddCodeSpecial{\eq@next}% +}% dpsj4 % \end{macrocode} % \end{macro} % \begin{macrocode} @@ -2398,6 +2521,7 @@ \exrtnlabelformat\fi}}% \protect\endeqEXt\ifeqforpaper\protect\par{\belowexsolnskip}\fi^^J% %</eqexam> + \ifmakeExSlLocal\protect\endgroup^^J\fi %<*package|eqexam> } % \end{macrocode} @@ -2406,46 +2530,69 @@ % Unless \cmd{\eq@solutionsaftertrue}, then \cmd{\endverbitim}, % and write return labels. % \begin{macrocode} -\def\endsolnexer@woparts{% - \if\currhideopt H% - \ifkeepdeclaredvspacing\vskip\sameVspace\fi - \csname endprocsoln\endcsname - \else +\let\eq@e@ddCodeSpecialDef\relax % dpsj4 +\let\eq@e@ddCodeSpecial\eq@e@ddCodeSpecialDef % dpsj6 +% \end{macrocode} +% Added \cs{kdvsp@Restore} to support +% the \texttt{flextended} option from \textsf{eqexam}. See the placement +% of this command below its default definition of \cs{relax}. +% \changes{v8.1i}{2018/01/20}{Added \string\cs{kdvsp@Restore} to support +% the \texttt{flextended} option from \string\textsf{eqexam}} +% \begin{macrocode} +\let\kdvsp@Restore\relax % dpsj20 +\def\endsolnexer@woparts{\endprocsoln\eq@e@ddCodeSpecial + \pkg@endsolnexerhook % djsj8 moved from the end of the macro + \ifeq@solutionsafter\else + \expandafter\endgroup\fi % from \begingroup at \solnexer@@@woparts + \global\let\exsolnonceonlytophook\relax + \ifx\sameVspace\@empty\gdef\sameVspace{0pt}\fi % dpsj5 + \ifvspacewithsolns\vspaceFmt{\sameVspace}\else + \ifeq@nosolutions\ifeq@solutionsafter\else + \vspaceFmt{\sameVspace}\fi\fi\fi + \if\currhideopt H% + \ifkeepdeclaredvspacing\vskip\sameVspace\fi +% \csname endprocsoln\endcsname + \else % \end{macrocode} % If solutions after, we start a new paragraph, then add some kerning glue, % this gives a better gauge for calculating the \cs{pagetotal}. % \begin{macrocode} - \ifeq@solutionsafter - \if\exerstar*% - \eq@fititin{\mbox{\exrtnlabelformatwp}}\else - \eq@fititin{\mbox{\exrtnlabelformat}}\fi - \ifx\istabularexer\eq@YES\kern0pt\else\par\fi -% \ifnum\exerwparts@cols>0\relax\kern0pt\else\par\fi -% \end{macrocode} -% \changes{v6.3z}{2011/04/28}{if \cs{ifkeepdeclaredvspacing} is true, we attempt + \ifeq@solutionsafter + \ifx\isitleadin\eq@YES\parshape=0 \fi % dpsj9 + \if\exerstar*% + \eq@fititin{\mbox{\exrtnlabelformatwp}}\else + \eq@fititin{\mbox{\exrtnlabelformat}}\fi + \ifx\istabularexer\eq@YES\unskip\kern0pt\else\par\fi % dpsj6 +% \ifx\istabularexer\eq@YES\kern0pt\else\par\fi +% \ifnum\exerwparts@cols>0\relax\kern0pt\else\par\fi +% \end{macrocode} +% if \cs{ifkeepdeclaredvspacing} is true, we attempt % to preserve the vertical space declared by the \textsf{solution} environment when -% \cs{ifeq@solutionsafter} is true.} +% \cs{ifeq@solutionsafter} is true. +% \changes{v6.3z}{2011/04/28}{if \string\cs{ifkeepdeclaredvspacing} is true, we attempt +% to preserve the vertical space declared by the \textsf{solution} environment when +% \string\cs{ifeq@solutionsafter} is true.} % \begin{macrocode} -\ifx\minVspacet@bs\@empty - \ifkeepdeclaredvspacing + \ifx\minVspacet@bs\@empty + \ifkeepdeclaredvspacing % \end{macrocode} % We get the current \cs{pagetotal}, and subtract off the page total as recorded % by \cs{eq@startSoln}. % \begin{macrocode} - \@tempdima\pagetotal - \advance\@tempdima-\eq@startSoln + \@tempdima\pagetotal + \advance\@tempdima-\eq@startSoln % \end{macrocode} % \changes{v6.4w}{2012/26/27}{Added \cs{relax} following the assignment.} % {\TeX} was looking ahead looking for the rest of the dimension, this caused % problems because later code was expanded when it should not have been. Inserted % \cs{relax}, \verb~\@tempdimb\sameVspace\relax~. % \begin{macrocode} - \@tempdimb\sameVspace\relax + \@tempdimb\sameVspace\relax % \end{macrocode} % if \cs{soln@keys@nLines} is nonempty, we put \cs{sameVspace} to \texttt{1sp}, % unless the author asks for \texttt{1sp}, this is how it is set. % \begin{macrocode} - \ifdim\@tempdimb>1sp\relax + \ifdim\@tempdimb>1sp\relax % \end{macrocode} % If there is a positive value for \cs{sameVspace}, we calculate % the difference between\cs{@tempdimab} and \cs{@tempdima}, that is, we calculate @@ -2453,35 +2600,37 @@ % \sameVspace-(\pagetotal-\eq@startSoln) %\end{verbatim} % \begin{macrocode} - \advance\@tempdimb-\@tempdima + \advance\@tempdimb-\@tempdima % \end{macrocode} % If this difference is positive, we will skip this amount. % \begin{macrocode} - \ifdim\@tempdimb>0pt\vglue\@tempdimb\kern0pt - \let\eqe@showEndHere\@gobble - \edef\tmp@exp{\noexpand\marginpar{% - \noexpand\smash{e: adj \the\@tempdimb}}}% - \eqe@debugVertSkip{\tmp@exp}% - \fi - \fi + \ifdim\@tempdimb>0pt\vglue\@tempdimb\kern0pt + \let\eqe@showEndHere\@gobble + \edef\tmp@exp{\noexpand\marginpar{% + \noexpand\smash{e: adj \the\@tempdimb}}}% + \eqe@debugVertSkip{\tmp@exp}% \fi - \eqe@showEndHere{\eqe@debugVertSkip{\marginpar{\smash{e}}}}% -\fi - \else - \endprocsoln - \eq@ckglobalhide - \ifeq@hidesolution\else - \endsolnexerhookaux + \fi + \fi + \eqe@showEndHere{\eqe@debugVertSkip{\marginpar{\smash{e}}}}% + \fi + \else +% \endprocsoln + \eq@ckglobalhide + \ifeq@hidesolution\else + \endsolnexerhookaux % \end{macrocode} % Here's were we write the trailer for the solution % \begin{macrocode} - \set@display@protect - \immediate\write\verbatim@out{\eqExerSolnTrailer}% - \set@typeset@protect - \fi + \let\verbatim@out\ex@solns + \set@display@protect + \immediate\write\verbatim@out{\eqExerSolnTrailer}% + \set@typeset@protect \fi + \fi \fi -\pkg@endsolnexerhook\endsolnexerhook} + \kdvsp@Restore % dpsj20 + \endsolnexerhook\penalty0\relax} % \end{macrocode} % \end{macro} % \subsection{The \texttt{exercise*} Environment: Exercises with Parts} @@ -2534,7 +2683,7 @@ % (2016/12/16) Define a flag \cs{istabularexer} that signals to the solution environment it is in a tab environment % \changes{v7.8b}{2016/12/16}{Added \string\cs{istabularexer}} % \begin{macrocode} -\let\istabularexer\eq@NO % dps 2016/12/16 +\let\istabularexer\eq@NO \def\exercise@parts{\let\rlspar\relax \ifx\solutionparshape\@empty \let\isitleadin\eq@NO @@ -2550,17 +2699,17 @@ % a leadinitem.} If there is a lead-in, we set \cs{topsep} to \texttt{0pt} % and skip \cs{itemsep}. % \begin{macrocode} - \def\eqparts@topsep{0pt}% dps88 - \vskip\eqparts@itemsep\relax\fi % dps88 + \def\eqparts@topsep{0pt}% + \vskip\eqparts@itemsep\relax\fi \topofpartshook - \let\itsExerParts\eq@YES % dps17 + \let\itsExerParts\eq@YES \global\let\@listiiredefined\eq@NO \def\exerwparts@cols{0}\@ifnextchar[% {% % \end{macrocode} % When there is a \cs{tableadin}, we remove \cs{removelastparskip} because it does not occur above. % \begin{macrocode} - \if@tableadinitem\else\removelastparskip\fi % dps11 + \if@tableadinitem\else\removelastparskip\fi % \keepdeclaredvspacingfalse \let\endparts\endexercise@parts@tabular\exercise@parts@tabular@}% {\let\endparts\endexercise@parts@list\exercise@parts@list}} @@ -2612,16 +2761,16 @@ % parts. %\changes{v6.4o}{2012/02/04} {Fine tune the control over space between parts.} % \begin{macrocode} -\newcommand{\partsitemsep}[1]{{% dps88 +\newcommand{\partsitemsep}[1]{{% \setlength{\@tempdima}{#1}% \xdef\eqparts@itemsep{\the\@tempdima}}} \let\eqpartsitemsep\partsitemsep \def\eqparts@itemsep{0pt} -\newcommand\partsparsep[1]{{% dps88 +\newcommand\partsparsep[1]{{% \setlength{\@tempdima}{#1}% \xdef\eqparts@parsep{\the\@tempdima}}} \def\eqparts@parsep{0pt} -\newcommand\partstopsep[1]{{% dps88 +\newcommand\partstopsep[1]{{% \setlength{\@tempdima}{#1}% \xdef\eqparts@topsep{\the\@tempdima}}} \def\eqparts@topsep{3pt} @@ -2694,9 +2843,9 @@ % (2012/11/30) If \cs{solutionparshape} is nonempty, the user has used % \cs{leadinitem}, so we increment \texttt{partno}. % \begin{macrocode} - \if\isitleadin\eq@YES % dps7 + \if\isitleadin\eq@YES \settowidth{\eq@tmplength}{\parts@indent\eqe@prtsepPrb}% - \xdef\prtsIndntSep{\the\eq@tmplength}% dps7 + \xdef\prtsIndntSep{\the\eq@tmplength}% % \advance\linewidth-\prtsIndntSep\relax \if\itsforleadinitem\eqe@YES\setcounter{partno}{\fliPartNo}\else \setcounter{partno}{1}\fi\fi @@ -2843,12 +2992,12 @@ % \end{macrocode} % If this is not tabular env, \cs{autotabnewline} does nothing % \begin{macrocode} - \ifnum\exerwparts@cols>0\relax % dps cq + \ifnum\exerwparts@cols>0\relax \ifx\eq@tabMarkChk\@gobble \def\eq@atnext{\expandafter \tabularnewline\expandafter[#1]}\else \def\eq@atnext{\resettabMark\tabularnewline - \noalign{\expandafter\kern#1}}\fi % dps7 + \noalign{\expandafter\kern#1}}\fi \expandafter\eq@atnext\fi} \def\eq@tabMark{% \ifnum\eq@extabColCnt=0\relax @@ -2886,7 +3035,7 @@ % \cs{leadinitem}, so we increment \texttt{partno}. % \begin{macrocode} \def\tablrIndent{\hglue\prtsIndntSep\relax}% - \if\isitleadin\eq@YES % dps7 + \if\isitleadin\eq@YES \if$\the\everypar$\let\tablrIndent\relax\fi \setcounter{partno}{1}\fi \let\leadinitem\eq@leadinitemparts @@ -2912,8 +3061,8 @@ \@ifundefined{@xtabularcr}{\let\@xarraycr\eq@xtabularcr} {\let\@xtabularcr\eq@xtabularcr}% % \end{macrocode} -% We reduce the width of the \cs{parbox}es (p|{width}|) by \cs{exertabsep} to leave -% room for \cs{tabcolsep=}\cs{exertabsep} between columns. +% We reduce the width of the \cs{parbox}es (p|{width}|) by \cs{eq@partstabcolsep} to leave +% room for \cs{tabcolsep=}\cs{eq@partstabcolsep} between columns. %\begin{verbatim} % n=\exerwparts@cols % width=(\linewidth-2*(n-1)*\tabcolsep)/n @@ -2935,15 +3084,16 @@ \tabcolsep\@tempdima \multiply\@tempdima\@tempcnta \advance\eq@tmpdima-\@tempdima - \divide\eq@tmpdima by\exerwparts@cols + \divide\eq@tmpdima by\exerwparts@cols\relax %dpsj3 % \ifx\isitleadin\eq@NO - \advance\eq@tmpdima\prtsIndntSep\relax -% \advance\eq@tmpdima\halfWidth\relax % dps17 +% \advance\eq@tmpdima\prtsIndntSep\relax % dpsj3 + \edef\widthOfPartsBox{\the\eq@tmpdima}% dpsj2 +% \advance\eq@tmpdima\halfWidth\relax % \else\advance\eq@tmpdima\halfWidth\relax\fi % \end{macrocode} % If there is a \cs{tableadin}, we do not perform a \cs{vskip}. % \begin{macrocode} - \if@tableadinitem\else\vskip\eq@partstabtopsep\relax\fi % dps11 + \if@tableadinitem\else\vskip\eq@partstabtopsep\relax\fi \noindent\normalbaselines\kern0pt \prior@parts@hook\abovepartshook % \end{macrocode} @@ -2952,6 +3102,7 @@ % \changes{v7.4}{2015/03/23}{inserted \cmd\setTabulrSolnEnv}% % \begin{macrocode} \tablrIndent\tabular[t]{@{}*{\exerwparts@cols}{>{\setTabulrSolnEnv +% \ifanswerkey\eqSolnExCmds\fi %dpsj2 \parskip\eqeques@parsep\relax \parindent0pt\relax\strut}p{\eq@tmpdima}}@{\hidewidth}}% }{\endtabular\kern0pt @@ -3006,7 +3157,7 @@ \eq@tmpdima=\wd\eq@tmpbox \addtolength\eq@tmplength{\eq@extralabelsep}% \xdef\partshangamount{\the\eq@tmplength}% - \advance\linewidth-\eq@tmplength +% \advance\linewidth-\eq@tmplength %dpsj3 \parshape \@ne 0pt \linewidth \everypar{\parshape \@ne 0pt \linewidth}% \eq@setPrbSolnAftrIndnt @@ -3036,6 +3187,8 @@ \eq@item } % \end{macrocode} +% End of the \texttt{parts} environment. +% \end{environment} % In the above tabular parts environment, \cs{@xtabularcr} is \cs{let} to % equal to \cs{eq@xtabularcr}. % \begin{macrocode} @@ -3055,10 +3208,6 @@ {\eqe@tab@parts@rowsep}}% \def\eqe@tab@parts@rowsep{\save@@xtabularcr \noalign{\expandafter\kern\eqparts@tabrowsep}}% -% \end{macrocode} -% End of the \texttt{parts} environment. -% \end{environment} -% \begin{macrocode} %</package|eqexam> %<*package> % \end{macrocode} @@ -3067,12 +3216,15 @@ % We provide several key-values for adjusting the spacing of the environment. % The keys defined here are \texttt{labelwidthTo}, \texttt{labelwidth}, \texttt{topsep}, % \texttt{parsep},\texttt{itemsep}, \texttt{labelsep}, and \texttt{continue}.% -% \IndexKey{labelwidthTo}\IndexKey{labelwidth}\IndexKey{topsep}% -% \IndexKey{parsep}\IndexKey{itemsep}\IndexKey{labelsep}\IndexKey{continue}% +% \IndexKey{labelwidthTo}\IndexKey{labelwidth} % \begin{macrocode} \define@key{exEnum}{labelwidthTo}[\normalsize\normalfont\bfseries00.\ ]% {\def\exE@labelwidthTo{#1}} \define@key{exEnum}{labelwidth}[\@empty]{\def\exE@labelwidth{#1}} +% \end{macrocode} +% Keys continued.\IndexKey{topsep}% +% \IndexKey{parsep}\IndexKey{itemsep}\IndexKey{labelsep}\IndexKey{continue}% +% \begin{macrocode} \let\exE@labelwidth\@empty \define@key{exEnum}{topsep}[3pt]{\def\exE@topsep{#1}} \define@key{exEnum}{parsep}[3pt]{\def\exE@parsep{#1}} @@ -3110,7 +3262,7 @@ \def\setENum{\Elabel\if\exerstar*\thequestionno(\thepartno)\else \thequestionno\fi}% \ifExSolutionsSet\else - \writeToExSolns{\protect\begin{exEnumerate}}\fi + \writeToExSolns{^^J\protect\begin{exEnumerate}^^J}\fi \list{}{% \ifx\exE@labelwidth\@empty \settowidth{\labelwidth}{\exE@labelwidthTo}\else @@ -3126,7 +3278,7 @@ \settowidth{\labelsep}{\normalfont\ }% \setlength{\leftmargin}{\labelwidth}% }\item\relax}{\ifExSolutionsSet\else - \writeToExSolns{\protect\end{exEnumerate}}\fi + \writeToExSolns{\protect\end{exEnumerate}^^J}\fi \endlist} % \end{macrocode} % \end{environment} @@ -3149,6 +3301,7 @@ % \end{environment} % \end{environment} % \begin{macrocode} +% End of enumeration exercises section %</package> %<*package|eqexam> % \end{macrocode} @@ -3306,7 +3459,7 @@ % to be redefined to \cs{newpage}. It is used in \cs{exerSolnHeader}. % The reasons for this definition are lost in time. % \begin{macrocode} - \def\webnewpage{\let\webnewpage\newpage}% + \def\webnewpage{\global\let\webnewpage\newpage}% \fi % \end{macrocode} % We have a prior command, followed by the section title @@ -3657,6 +3810,7 @@ %\DescribeMacro\sqhspace\cmd\sqhspace\ is the space that follows \cmd\sqlabel % \begin{macrocode} \let\sqhspace\space +\let\ListOfSQuizNames\@empty \newenvironment{shortquiz} {% % \end{macrocode} @@ -3732,10 +3886,19 @@ \oField.WrongAnsSymbJSLoc=\wrngAnsSymbJSLoc;\fi }}]{sqID\oField}{0bp}{0bp}}% } +\def\qz@IDTxtField{\makebox[0pt][l]{\textField[\autoCenter{n}\BC{}\BG{} + \S{S}\textSize{0}\Ff{\FfReadOnly} + \AA{\AAFormat{if(typeof aQuizzesInDoc=="undefined")\r\t + var aQuizzesInDoc=new Array();\r + if (aQuizzesInDoc.indexOf("\oField")) aQuizzesInDoc.push("\oField"); + }}]{qzID\oField}{0bp}{0bp}}} %</package> %<*package|eqexam> +\let\eqQuizType\relax \def\@@shortquiz[#1]{%\begingroup \gdef\oField{#1}\gdef\curr@quiz{#1}\gdef\currQuiz{#1}% + \edef\tmp@Exp{\noexpand\g@addto@macro\noexpand + \ListOfSQuizNames{,#1}}\tmp@Exp % \end{macrocode} % We try to support {\LaTeX}'s cross-referencing system by defining % \cs{@currentlabel}, \cs{@currentHlabel}, and \cs{@currentlabelname}. @@ -3892,6 +4055,16 @@ % \DescribeMacro\sqsolafterhspace The space after the solution label % \begin{macrocode} \def\sqsolafterhspace{\space} +% \end{macrocode} +% When solutions are written to the QSL file, they are not normally in a group. +% If you execute \DescribeMacro\makeQzSolnsLocalOn\cs{makeQzSolnsLocalOn}, each solution +% is written in a group. Undo this with \DescribeMacro\makeQzSolnsLocalOff\cs{makeQzSolnsLocalOff}, +% which is the historic default. +% \changes{v8.1p}{2018/02/13}{Added grouping for quiz solutions to the QSL file} +% \begin{macrocode} +\newif\ifmakeQzSlLocal \makeQzSlLocalfalse +\def\makeQzSolnsLocalOn{\makeQzSlLocaltrue} +\def\makeQzSolnsLocalOff{\makeQzSlLocalfalse} \def\solution@sq{\let\eq@next\relax \ifx\@qzsolndest\@empty \PackageWarning{exerquiz}% @@ -3907,6 +4080,7 @@ \global\therearequizsolutionstrue\let\verbatim@out=\quiz@solns \set@display@protect \immediate\write\verbatim@out{% + \ifmakeQzSlLocal\protect\begingroup^^J\fi % \end{macrocode} % Mark in the solutions files whether this is a quiz or a shortquiz solution. % \begin{macrocode} @@ -3963,9 +4137,8 @@ \else\newpage\penalty1\fi\fi\egroup } % \end{macrocode} -% \begin{macro}{\saveDest} -% \begin{macro}{\useDest} -% These two macros are used, as needed to save the destination name of a solution, then +% The two macros\DescribeMacro{\saveDest}\cs{saveDest} and \DescribeMacro{\useDest}\cs{useDest} are used, +% as needed to save the destination name of a solution, then % re-emitting it later, just prior to the solution. Useful for grouped questions. % \begin{macrocode} \newcommand{\saveDest}[1][]{% @@ -3974,10 +4147,6 @@ \xdef\@qzsolndest{#1}\xdef\holdDest{#1}\fi} \def\useDest{\def\@qzsolndest{\holdDest}} \let\holdDest\@empty -% \end{macrocode} -% \end{macro} -% \end{macro} -% \begin{macrocode} %</package> %<*package|eqexam> \def\fpAfterSolutionsSkip{\par\medskip} @@ -3994,6 +4163,7 @@ {\protect\mbox{\sqslrtnlabel}}\string\endeqSQt% \fi \ifeqforpaper\protect\fpAfterSolutionsSkip\fi^^J% + \ifmakeQzSlLocal\protect\endgroup^^J\fi } %</package|eqexam> %<*package> @@ -4014,6 +4184,7 @@ %\end{document} %\end{verbatim} % \begin{macrocode} +% End package and begin package|eqexam %</package> %<*package|eqexam> \let\eqSQt\@gobble @@ -4070,8 +4241,7 @@ % \end{macrocode} % \end{macro} % \end{macro} -% \begin{macro}{\noPeekAction} -% The default definition of \cmd{quizSolnHeader} contains a macro called +% The\DescribeMacro{\noPeekAction} default definition of \cs{quizSolnHeader} contains a macro called % \cmd{\noPeek}. This is the action that \cmd{\noPeek} performs. The actual % definition of \cmd{\noPeek} is driver dependent, and is listed elsewhere. % An open page action will be created with a JavaScript action, which calls @@ -4083,16 +4253,15 @@ \def\noPeekAction#1#2{% /AA <</O<</S/JavaScript/JS(noPeek("#1",#2))>> >> } +%</package> +%<*package|eqexam> % \end{macrocode} -% \end{macro} % \subsection{The \texttt{shortquiz} Solutions} % When the first solution is written, \cmd{\therearequizsolutions} is % made true. When the solutions are input back into the file, and % this switch is still false, then no quiz header is typeset; % this avoids an empty quiz solutions section with only the header. % \begin{macrocode} -%</package> -%<*package|eqexam> \newif\iftherearequizsolutions \therearequizsolutionsfalse \let\aeb@FLOverride\relax % \end{macrocode} @@ -4140,7 +4309,7 @@ % \begin{macrocode} \newcommand{\quizSolnInput} {% - \let\webnewpage\relax + \global\let\webnewpage\relax \immediate\closeout\quiz@solns \ifeq@noquizsolutions\else % \end{macrocode} @@ -4154,7 +4323,7 @@ \iftherearequizsolutions\newpage\markright{}% \eq@normallheader\markright{\sqslsecrunhead}% \ifx\webnewpage\relax - \def\webnewpage{\let\webnewpage\newpage}\fi + \def\webnewpage{\global\let\webnewpage\newpage}\fi % \end{macrocode} % Here we have various prior commands, and the setting of the % section title. @@ -4255,6 +4424,7 @@ % For multiple choice questions, here we give the option of using a mixture of links % and forms. % \begin{macrocode} +% Begin joint package and eqexam %</package> %<*package|eqexam> \newcommand\useForms{\def\aeb@FLOverride{f}} @@ -4290,6 +4460,13 @@ {\goodbreak\@ifstar{\gdef\qstar{*}\@quiz*f}{\gdef\qstar{x}\@quiz*l}} {\aeb@endquiz} \def\@quizCnt{0} +% \end{macrocode} +% \cs{ListOfQuizNames} and \cs{ListOfSQuizNames} are master lists of all +% quizzes in the document. +% \changes{v7.8l}{2017/07/29}{Added \string\cs{ListOfQuizNames} and +% \string\cs{ListOfSQuizNames}} +% \begin{macrocode} +\let\ListOfQuizNames\@empty \def\@quiz*#1#2{% % \end{macrocode} % (06/08/10) The next two lines initialize the macros for registering the @@ -4329,9 +4506,11 @@ % \end{macrocode} % \changes{v6.3u}{2010/11/04}{% % Added \cs{xdef}\cs{oField}\texttt{\{\#2\}}, this is -% needed for \textsf{apb.dtx}. -%} +% needed for \textsf{apb.dtx}} +% Add \cs{listOfQuizNames} to track quizzes +% \changes{v7.8k}{2017/07/25}{Added \string\cs{listOfQuizNames} to track quizzes} % \begin{macrocode} + \g@addto@macro\ListOfQuizNames{,#2}% \gdef\quiz@total{#2}\xdef\curr@quiz{#2}\xdef\oField{#2}% \xdef\currQuiz{#2}\xdef\currQuizStartPage{\thepage}% \xdef\aPointType{0}% @@ -4434,9 +4613,9 @@ % \end{macrocode} % \end{macro} % \begin{macrocode} -\def\listOfQuizzes{} -\def\listOfSubmitQuizzes{} -\def\initializeAllSubmitQuizzes{} +%\def\listOfQuizzes{} +%\def\listOfSubmitQuizzes{} +%\def\initializeAllSubmitQuizzes{} % \end{macrocode} % \begin{macro}{\@initQuiz} % \begin{macro}{\priorInitQuiz} @@ -4444,7 +4623,7 @@ % \cs{@initQuiz} is executed when you click on `Begin Quiz'. Included here are some % macro hooks for insert code prior to, and after the quiz initialization. This % command appears in the commands \cs{eq@@BeginQuizLinkActions} and \cs{eq@@BeginQuizButtonActions} below. -%\changes{v7.0}{2014/11/05}{Added some JS: lstOfQuizzes is an associative array +%\changes{v7.0}{2014/11/05}{Added some JS: lstOfQuizzes is an object % listing all quizzes in the document, the value is the quiz object. We add properties % isSubmitted and initializeWith to the quiz object.} % \begin{macrocode} @@ -4459,7 +4638,7 @@ \oField.RightColorJSLoc=\rghtColorJSLoc;\fi \ifx\wrngColorJSLoc\@empty\else\jsR \oField.WrongColorJSLoc=\wrngColorJSLoc;\fi - \ifx\partialColorJSLoc\@empty\else\r + \ifx\partialColorJSLoc\@empty\else\jsR \oField.PartialColorJSLoc=\partialColorJSLoc;\fi \ifx\rghtAnsSymbJSLoc\@empty\else\jsR \oField.RightAnsSymbJSLoc=\rghtAnsSymbJSLoc;\fi @@ -4469,7 +4648,9 @@ \oField.CorrAnsSymbJSLoc=\corrAnsSymbJSLoc;\fi \ifx\eqGradeScaleLoc\@empty\else\jsR \oField.GradeScaleLoc=new Array(\eqGradeScaleLoc);\fi - \ifx\priorInitQuiz\@empty\else\jsR\priorInitQuiz\fi\jsR + \ifx\eqCorrLocalChoiceFully\@empty\else\jsR % dpsf07 + \oField.fullyCorrectLoc=\eqCorrLocalChoiceFully;\fi + \ifx\priorInitQuiz\@empty\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 @@ -4512,6 +4693,7 @@ \let\bqlabelFmt\@empty \def\eq@BeginQuizLink {% + \qz@IDTxtField \set@@Link{}{}{}{\color{\@linkcolor}\bqlabelFmt\bqlabel}{}% {\eq@setWidgetProps\setLink@driver}% {\eq@BeginQuizLinkDefaults\eq@@BeginQuizLinkActions\every@Link}% @@ -4524,28 +4706,28 @@ % \begin{macrocode} \newcommand\priorSubmitQuiz{} \newcommand\postSubmitQuiz{} -\def\eq@@EndQuizLinkActions -{% - \A{\JS{% - if (!isQuizInitialized("\curr@quiz"))\jsR\jsT - eqAppAlert(InitMsg("\bqlabelISO"),3);\jsR - else {\jsR\jsT - if (\minQuizResp(\thequestionno)) {\jsR\jsT\jsT - \curr@quiz.PtValues=new % -Array(\pointValuesArray);\jsR\jsT\jsT - ProbType = [\ptypeArray];\jsR\jsT\jsT +\def\eq@@EndQuizLinkActions{\A{\JS{% + if (!isQuizInitialized("\curr@quiz"))\jsR\jsT + eqAppAlert(InitMsg("\bqlabelISO"),3);\jsR + else {\jsR\jsT + if (\minQuizResp(\thequestionno)) {\jsR\jsT\jsT + \curr@quiz.PtValues=new % + Array(\pointValuesArray);\jsR\jsT\jsT + ProbType = [\ptypeArray];\jsR\jsT\jsT \if@inclkey - \curr@quiz.CorrAns=(new % -Array(\corrAnsArray));\jsR\jsT\jsT + \curr@quiz.CorrAns=(new % + Array(\corrAnsArray));\jsR\jsT\jsT \fi - DisplayQuizResults("\curr@quiz",\theeqpointvalue,% -\thequestionno);\jsR\jsT\jsT -% \priorSubmitQuiz - \eq@submitURL - \postSubmitQuiz - resetQuiz("\curr@quiz");\jsR\jsT - }\jsR - }}}% + DisplayQuizResults("\curr@quiz",\theeqpointvalue,% + \thequestionno);\jsR\jsT\jsT + var h=this.getField("ScoreData.\curr@quiz");\jsR\jsT\jsT + h.value=Score+";"+NQuestions+";"% + +ptScore+";"+NPointTotal;\jsR\jsT\jsT + \eq@submitURL + \postSubmitQuiz + \jsT\jsT resetQuiz("\curr@quiz");\jsR\jsT + }\jsR + }}}% } \def\eq@EndQuizLinkDefaults{\Border{0 0 0}} \let\eqlabelFmt\@empty @@ -4560,8 +4742,8 @@ Array(\corrAnsArray));\jsR\jsT\jsT {\eq@EndQuizLinkDefaults\eq@@EndQuizLinkActions\every@Link}% \makebox[0pt][r]{\textField[\BC{}\autoCenter{n}]% {htxtfld.\curr@quiz}{0bp}{0bp}}% - \makebox[0pt][r]{\eq@insertHiddenFields}\global\let\eq@CGI\@empty - \ignorespaces + \makebox[0pt][r]{\eq@hiddenScoreData\eq@insertHiddenFields}% + \global\let\eq@CGI\@empty\ignorespaces } % \end{macrocode} % \end{macro} @@ -4580,14 +4762,12 @@ Array(\corrAnsArray));\jsR\jsT\jsT \def\eq@@BeginQuizButtonActions {% \A{\JS{% -% \ifx\priorInitQuiz\@empty\else\priorInitQuiz\r\fi \@initQuiz -% \ifx\postInitQuiz\@empty\else\r\postInitQuiz\fi }}% } \newcommand\eq@BeginQuizButton[1][] {% - \mbox{\push@@Button{#1}{beginQuiz.\curr@quiz}{}% + \mbox{\qz@IDTxtField\push@@Button{#1}{beginQuiz.\curr@quiz}{}% {\DefaultHeightOfWidget}{\eq@protect\A}% {\eq@setButtonProps\eq@Button@driver}% {\BeginQuizButtonDefaults\eq@@BeginQuizButtonActions @@ -4603,29 +4783,31 @@ Array(\corrAnsArray));\jsR\jsT\jsT \CA{\eqlabel}\F{\FPrint}\BC{1 0 0} \BG{.7529 .7529 .7529}\W{1}\S{B}\H{P} } -\def\eq@@EndQuizButtonActions -{% - \A{\JS - {if (!isQuizInitialized("\curr@quiz"))\jsR\jsT - eqAppAlert(InitMsg("\bqlabelISO"),3);\jsR - else {\jsR\jsT - if (\minQuizResp(\thequestionno)&&_ModalNotOn){\jsR\jsT\jsT - \curr@quiz.PtValues=(new % -Array(\pointValuesArray));\jsR\jsT\jsT - ProbType=[\ptypeArray];\jsR\jsT\jsT +\def\eq@@EndQuizButtonActions{\A{\JS{% + if (!isQuizInitialized("\curr@quiz"))\jsR\jsT + eqAppAlert(InitMsg("\bqlabelISO"),3);\jsR + else {\jsR\jsT + if (\minQuizResp(\thequestionno)&&_ModalNotOn){\jsR\jsT\jsT + \curr@quiz.PtValues=(new % + Array(\pointValuesArray));\jsR\jsT\jsT + ProbType=[\ptypeArray];\jsR\jsT\jsT \if@inclkey - \curr@quiz.CorrAns=(new % -Array(\corrAnsArray));\jsR\jsT\jsT + \curr@quiz.CorrAns=(new % + Array(\corrAnsArray));\jsR\jsT\jsT \fi - DisplayQuizResults("\curr@quiz",\theeqpointvalue,% -\thequestionno);\jsR\jsT\jsT - \eq@submitURL - \postSubmitQuiz - resetQuiz("\curr@quiz");\jsR\jsT - }\jsR - }}% - } -} + DisplayQuizResults("\curr@quiz",\theeqpointvalue,% + \thequestionno);\jsR\jsT\jsT + var h=this.getField("ScoreData.\curr@quiz");\jsR\jsT\jsT + h.value=Score+";"+NQuestions+";"% + +ptScore+";"+NPointTotal;\jsR\jsT\jsT + \eq@submitURL + \postSubmitQuiz + \jsT\jsT resetQuiz("\curr@quiz");\jsR\jsT + }\jsR + }}}% +} +\newcommand{\eq@hiddenScoreData}{\makebox[0pt][r]{% + \textField[\BC{}\F{\FHidden}]{ScoreData.\curr@quiz}{0bp}{0bp}}} \newcommand\eq@EndQuizButton[1][] {% \ifx\eq@CGI\@empty @@ -4637,7 +4819,8 @@ Array(\corrAnsArray));\jsR\jsT\jsT {\eq@setButtonProps\eq@Button@driver}% {\EndQuizButtonDefaults\eq@@EndQuizButtonActions \every@ButtonField\every@EndQuizButton}}% - \makebox[0pt][r]{\eq@insertHiddenFields}\global\let\eq@CGI\@empty + \makebox[0pt][r]{\eq@hiddenScoreData\eq@insertHiddenFields}% + \global\let\eq@CGI\@empty } % \end{macrocode} % \end{macro} @@ -5000,12 +5183,11 @@ Array(\corrAnsArray));\jsR\jsT\jsT % text macro \cs{currQuiz} which contains the quiz name. Can be used in conjunction % with \cs{floatQuiz} and \cs{startQuizHere}. % } +% \changes{v8.1k}{2018/02/04}{Added \string\cs{oField} to list in \string\cs{DeclareQuiz}} % \begin{macrocode} -\def\DeclareQuiz#1{% - \edef\thisQuiz{#1}% - \edef\curr@quiz{#1}% - \edef\currQuiz{#1}% - \edef\curr@quiz{#1}% +\def\DeclareQuiz#1{\edef\oField{#1}% + \edef\thisQuiz{#1}\edef\curr@quiz{#1}% + \edef\currQuiz{#1}\edef\curr@quiz{#1}% } \let\Quiz\DeclareQuiz % \end{macrocode} @@ -5393,6 +5575,7 @@ Array(\corrAnsArray));\jsR\jsT\jsT % `\texttt*', in which case a name of \texttt{\string\curr@quiz.\string\thequestionno} % is assigned. % \begin{macrocode} +% Begin joint package and eqexam %</package> %<*package|eqexam> \def\pushEnvir{\xdef\eq@currenvir{\@currenvir}\endgroup} @@ -5486,7 +5669,7 @@ Array(\corrAnsArray));\jsR\jsT\jsT \def\eq@lw@l{\eq@l@l\eq@hspanner} % \end{macrocode} % For the link-style MC question, the default width, \cs{eq@l@l}, of the label is the normalsize width of -% `(d)'. For a form checkbox or radiobutton bux, the default width, cs{eq@lw@f}, is \cs{RadioFieldSize}, +% `(d)'. For a form checkbox or radiobutton, the default width, \cs{eq@lw@f}, is \cs{RadioFieldSize}, % normally defined as \texttt{11bp}. % \begin{macrocode} \def\eq@l@l{\normalsize\normalfont(d)} @@ -5517,8 +5700,8 @@ Array(\corrAnsArray));\jsR\jsT\jsT \noexpand\eq@ansChoiceArray{,"\alph{quizno}"}}\fi \tmp@exp } -\newcommand\Ans@list[2][0]{\gdef\eq@pPTs{#1}% - \xdef\Ans@choice{#2}\item\relax\noindent\if\eq@listType\eq@One +\newcommand\Ans@list[2][0]{\gdef\eq@pPTs{#1}\xdef\Ans@choice{#2}% + \item\relax\noindent\if\eq@listType\eq@One \addtocounter{quizno}{-1}\@ifundefined{ifwithsoldoc} {\refstepcounter{quizno}}{\ifwithsoldoc\stepcounter{quizno}\else \refstepcounter{quizno}\fi}\fi @@ -5552,7 +5735,7 @@ Array(\corrAnsArray));\jsR\jsT\jsT % to 0pt; when \textsf{eqexam} is used, it has a nonzero value. % \begin{macrocode} \ifnum\exerwparts@cols>1\relax - \ifx\itsExerParts\eq@YES % dps17 + \ifx\itsExerParts\eq@YES \setlength{\leftmargin}{\labelwidth}\else \setlength{\leftmargin}{\labelwidth+\eqemargin}\fi \else @@ -5569,6 +5752,7 @@ Array(\corrAnsArray));\jsR\jsT\jsT % another for \texttt{exerquiz}. % to the following. % \begin{macrocode} +% Begin joint package and eqexam %</package|eqexam> %<package> \setlength{\labelsep}{0pt}% %<package>% \settowidth{\labelsep}{\eq@hspanner}% @@ -5588,8 +5772,8 @@ Array(\corrAnsArray));\jsR\jsT\jsT % These parameters are saved in the commands \cs{eq@pPTs} and % \cs{Ans@choice}. % \begin{macrocode} -\newcommand\Ans@tabular[2][0]{\gdef\eq@pPTs{#1}% - \xdef\Ans@choice{#2}\leavevmode\@Ans +\newcommand\Ans@tabular[2][0]{\gdef\eq@pPTs{#1}\xdef\Ans@choice{#2}% + \leavevmode\@Ans } % \end{macrocode} % (2013/05/17) \DescribeMacro{\sqtabsep} sets the \cs{tabsep} between columns. @@ -5602,7 +5786,7 @@ Array(\corrAnsArray));\jsR\jsT\jsT \def\sqTabPos#1{\def\sq@TabPos{[#1]}}\sqTabPos{} \def\answers@@sq@tabular#1{% % \ifinner\else\par\vskip-\parskip\vspace{\aboveanswersSkip}\fi - \ifinner % dps17 + \ifinner \ifx\itsExerParts\eq@YES\par\removelastskip \removelastparskip\vskip\aboveanswersSkip\fi \else\par\removelastskip\removelastparskip @@ -5796,42 +5980,28 @@ Array(\corrAnsArray));\jsR\jsT\jsT \def\sqNoCorrections{\let\@sqAlertsOnly\eq@One} \def\sqCorrections{\let\@sqAlertsOnly\eq@Zero} \sqNoCorrections +\def\Ans@sq@f@ActionsTrue{% + \if\@sqTurnOffAlerts1OnBlurRespBox(true,"\oField");\jsR\fi + \ifx\@qzsolndest\@empty\else\ifeq@solutionsafter\else + jmpToNamedDest("\oField","\@qzsolndest",% + \if\@sqTurnOffAlerts00\else1\fi);\fi + \fi\eqAddAAMouseUpMC} +\def\Ans@sq@f@ActionsFalse{% + \if\@sqTurnOffAlerts1OnBlurRespBox(false,"\oField" );\jsR\fi + \ifx\oField\@empty\else + updateTally("\oField.\thequestionno"); + \fi\jsR\eqAddAAMouseUpMC} % \end{macrocode} % The actions for the form version of a multiple choice question of a \texttt{shortquiz}. % \begin{macrocode} -\def\Ans@sq@f@Actions -{% - \A{\if\Ans@choice\eq@One - \JS{% -% \end{macrocode} -%\changes{v6.7d}{2013/05/27}{removed JS control of checks and color, they -% are hardwired instead.} -% \begin{macrocode} - \if\@sqTurnOffAlerts1OnBlurRespBox(true,"\oField");\jsR\fi - \ifx\@qzsolndest\@empty\else - \ifeq@solutionsafter\else - jmpToNamedDest("\oField","\@qzsolndest",% -\if\@sqTurnOffAlerts00\else1\fi);\fi - \fi}% - \else - \JS{% - \if\@sqTurnOffAlerts1OnBlurRespBox( false, % -"\oField" );\jsR\fi - \ifx\oField\@empty\else - updateTally("\oField.\thequestionno"); - \fi}% - \fi% - }% - \AA{\AAMouseDown{\JS{% - updateTally.downState=!!event.target.isBoxChecked% -(\arabic{quizno}-1);}}}% -} -\def\Ans@proofing -#1{% - \ifeq@proofing\if\Ans@choice1\relax - \llap{\@proofingsymbol\,\hskip#1\relax}% - \fi\fi -} +\def\Ans@sq@f@Actions{\A{\if\Ans@choice\eq@One + \JS{\Ans@sq@f@ActionsTrue}\else + \JS{\Ans@sq@f@ActionsFalse}\fi}% + \AAmousedown{updateTally.downState=!!event.target.isBoxChecked% + (\arabic{quizno}-1);}} +\def\Ans@proofing#1{\ifeq@proofing\if\Ans@choice1\relax + \llap{\@proofingsymbol\,\hskip#1\relax}% + \fi\fi} % \end{macrocode} %\DescribeMacro{\sqRghtSymbChoice}\DescribeMacro{\sqRghtSymbColor} for the \texttt{shortquiz} % environment, these first two commands assign the right symbol (default check) and @@ -5947,52 +6117,48 @@ Array(\corrAnsArray));\jsR\jsT\jsT \catcode`\&=12 \gdef\eq@AND{&&} \endgroup -\def\Ans@ck@sq@f@Actions -{% - \A{\if\Ans@choice1% - \JS{% -var fName=event.target.name;\jsR -var g=this.getField("mc.\oField.\thequestionno");\jsR -var a=g.getArray();\jsR -for (var i=0; i<a.length; i++)\jsR\jsT - if ( a[i].isBoxChecked(0) \eq@AND\space -a[i].value.charAt(0)==0)\jsR\jsT\jsT - a[i].checkThisBox(0,false);\jsR - \if\@sqTurnOffAlerts1OnBlurRespBox( % - true, "\oField" );\jsR\fi - \ifx\@qzsolndest\@empty\else - \ifeq@solutionsafter\else -% if all correct answers are check, jump to solution -for (var i=0; i<a.length; i++){\jsR\jsT - if ( a[i].exportValues[0].charAt(0)==1 \eq@AND\space -!a[i].isBoxChecked(0) )\jsR\jsT\jsT - break;\jsR -}\jsR - if (i>=a.length) jmpToNamedDest("\oField","\@qzsolndest",% - \if\@sqTurnOffAlerts00\else1\fi); - \fi - \fi}% - \else% - \JS{% -var fName=event.target.name;\jsR -var g=this.getField("mc.\oField.\thequestionno");\jsR -var a=g.getArray();\jsR -for (var i=0; i<a.length; i++)\jsR -{\jsR\jsT - if (a[i].value.charAt(0)==0) {\jsR\jsT\jsT - if ( fName != a[i].name )\jsR\jsT\jsT\jsT - a[i].checkThisBox(0,false);\jsR\jsT - }\jsR -}\jsR - \if\@sqTurnOffAlerts1OnBlurRespBox( false, "\oField" );\fi% - \ifx\oField\@empty\else% - updateTally("\oField.\thequestionno"); - \fi}% - \fi% - }% - \AA{\AAMouseDown{% -\JS{updateTally.downState=!!event.target.isBoxChecked(0);}}} -} +\def\Ans@ck@sq@f@ActionsTrue{% + var fName=event.target.name;\jsR + var g=this.getField("mc.\oField.\thequestionno");\jsR + var a=g.getArray();\jsR + for (var i=0; i<a.length; i++)\jsR\jsT + if ( a[i].isBoxChecked(0) \eq@AND\space + a[i].value.charAt(0)==0)\jsR\jsT\jsT + a[i].checkThisBox(0,false);\jsR + \if\@sqTurnOffAlerts1OnBlurRespBox(% + true,"\oField");\jsR\fi + \ifx\@qzsolndest\@empty\else + \ifeq@solutionsafter\else + % if all correct answers are check, jump to solution + for (var i=0; i<a.length; i++){\jsR\jsT + if ( a[i].exportValues[0].charAt(0)==1 \eq@AND\space + !a[i].isBoxChecked(0))\jsR\jsT\jsT + break;\jsR + }\jsR + if (i>=a.length) jmpToNamedDest("\oField","\@qzsolndest",% + \if\@sqTurnOffAlerts00\else1\fi); + \fi + \fi\eqAddAAMouseUpMS} +\def\Ans@ck@sq@f@ActionsFalse{% + var fName=event.target.name;\jsR + var g=this.getField("mc.\oField.\thequestionno");\jsR + var a=g.getArray();\jsR + for (var i=0; i<a.length; i++)\jsR + {\jsR\jsT + if (a[i].value.charAt(0)==0) {\jsR\jsT\jsT + if ( fName != a[i].name )\jsR\jsT\jsT\jsT + a[i].checkThisBox(0,false);\jsR\jsT + }\jsR + }\jsR + \if\@sqTurnOffAlerts1OnBlurRespBox( false, "\oField" );\fi + \ifx\oField\@empty\else + updateTally("\oField.\thequestionno"); + \fi\eqAddAAMouseUpMS} +\def\Ans@ck@sq@f@Actions{% + \A{\if\Ans@choice\eq@One + \JS{\Ans@ck@sq@f@ActionsTrue}\else + \JS{\Ans@ck@sq@f@ActionsFalse}\fi}% + \AAmousedown{updateTally.downState=!!event.target.isBoxChecked(0);}} \def\Ans@ck@sq@f{% \if\eq@listType\eq@One\stepcounter{quizno}\else \@ifundefined{ifwithsoldoc}{\refstepcounter{quizno}} @@ -6604,6 +6770,7 @@ if (_bOK) {\jsR\jsT % \end{macrocode} % \end{macro} % \begin{macrocode} +% Begin joint package and eqexam %</package> %<*package|eqexam> % \end{macrocode} @@ -6983,9 +7150,11 @@ if (_bOK) {\jsR\jsT % \end{macrocode} % \end{macro} % \begin{macrocode} +% end joint package and eqexam %</package|eqexam> % \end{macrocode} % \begin{macrocode} +% Begin randomize segment %<*randomize> % \end{macrocode} % @@ -7029,6 +7198,13 @@ if (_bOK) {\jsR\jsT \endgroup } % \end{macrocode} +% \DescribeMacro{\writeSeedToSolnFile} writes the current +% value of \cs{randomi} to the solution file. May be useful in randomizing choices +% in the solution file in the same order they were randomized in the main document. +% \changes{v7.8h}{2017/04/14}{Added \string\cs{writeSeedToSolnFile}} +% \begin{macrocode} +\def\writeSeedToSolnFile{\writeToExSolns{\string\randomi=\the\randomi}} +% \end{macrocode} % The \cs{bChoices} command is now processed by the \texttt{keyval} package. There % are two keys: \texttt{nCols} and \texttt{random}. The first key % sets the number of columns we are limited to; the second one obviously declares @@ -7386,12 +7562,6 @@ if (_bOK) {\jsR\jsT % In the case of the author using Acrobat 4.0, he/she needs to load % manually insert the \texttt{eq\_DLJS.pdf} file. If only exercises % are used, this insertion is not needed. -% \begin{macrocode} -%</package> -% \end{macrocode} -% \begin{macrocode} -%<*package> -% \end{macrocode} % \begin{environment}{oQuestion} % This was my first attempt and I have not deleted it from the package yet. % Useful for posing a single question only. The argument is the (unique) name @@ -7410,8 +7580,8 @@ if (_bOK) {\jsR\jsT \xdef\eq@pageThisQ{\the\c@page}% \global\let\eqQzQuesList\@empty \xdef\oField{#1}\xdef\curr@quiz{#1}\xdef\currQuiz{#1}% - \let\@qzsolndest\@empty - \stepcounter{questionno}% + \g@addto@macro\ListOfSQuizNames{,#1}\let\@qzsolndest\@empty +% \stepcounter{questionno}% \let\eqQuizType\isSQZ\gdef\eqPTs{1}\global\let\eqQT\eq@na \let\answers\answers@sq \let\endanswers\endanswers@sq @@ -7425,6 +7595,7 @@ if (_bOK) {\jsR\jsT \global\let\aebtitleQuiz\@empty \global\let\aebTitleQuiz\@empty \global\let\eq@tq@star\relax + \aftergroup\ignorespaces } \def\oSolution#1{\edef\@qzsolndest{#1}} % \end{macrocode} @@ -7497,6 +7668,24 @@ if (_bOK) {\jsR\jsT % \texttt{(r:x,r:y,i:n)}, where \texttt{"r"} means a real variable and \texttt{"i"} % means an integer variable. The variables must be either of the old style (no commas, no typing) % or the new style. Do not mix the styles. +% +% \changes{v8.0}{2017/08/08}{Support for multi-letter variables and alternate appearances} +% \textbf{Multi-letter variables.} Beginning with v8.0 (2017/08/08) support for multi-letter variables and appearance replacement +% is added. Within the \texttt{\#3}, use the following notation: +%\begin{verbatim} +% (x\rpl{alpha}{y}z) +%\end{verbatim} +%This declares three variables, \texttt{x}, \texttt{alpha}, and \texttt{z}. What in fact is +%taking place is that \texttt{alpha} is replaced by \texttt{y} and processing continues from there. +% +% \textbf{Alternate appearances.} Additionally, there is now a scheme for replacing the variables +% with alternate appearances. +%\begin{verbatim} +% (x\rpl{alpha->\\u03B1}{y}z) +%\end{verbatim} +%The arrow notation (\texttt{->}) tells \pkg{exerquiz} to replace \texttt{alpha} with the unicode character +%\verb~\u03B1~ (note the double backslash above), which is the Greek letter alpha ($\alpha$). +% % \item[\ttfamily\#4 :] Optional, a named destination to the solution to the % question. If this parameter appears, then a solution must follow the % question, enclosed in a \texttt{solution} environment. @@ -7529,36 +7718,101 @@ if (_bOK) {\jsR\jsT %\begin{flushleft}\footnotesize %|\RespBoxMath{<exp(t), 2*t, sin(t)>}(t)[soln]{3}{.0001}{0}{1}[compare]*{ProcVec}| %\end{flushleft} -% \begin{macrocode} -\newcommand\RespBoxNT{\def\rbFlag{0}\@RespBox} -\newcommand\RespBox{\def\rbFlag{0}\@RespBox} -\newcommand\RespBoxMath{\def\rbFlag{0}\@RespBox} -% \end{macrocode} -% These commands can be used define the default appearance of the \cs{RespBoxMath}, -% \cs{RespBoxTxt} et al. This first set controls all standard text fields. -% \begin{macrocode} +% \changes{v8.1}{2017/09/02}{Sanitize superscript before reading parameters in \string\cs{RespBoxMath}} +% \begin{macrocode} +\newcommand\RespBoxNT{\RespBoxMath} +\newcommand\RespBox{\RespBoxMath} +% \end{macrocode} +% (2018/03/21) Exclude unicode from \cs{RespBoxMath} +% \changes{v8.2.2}{2018/03/21}{Exclude unicode from \string\cs{RespBoxMath}} +% \begin{macrocode} +\newcommand\RespBoxMath{\def\rbFlag{0}\begingroup\Hy@unicodefalse + \@makeother\^\@makeother\&\@RespBox} +% \end{macrocode} +% Within \cs{RespBoxMath}, \cs{rpl} (\cs{rpl=\texttt{\underbar{r}e\underbar{pl}ace}}) is \cs{let} to \cs{eq@rpl}. The command \cs{rpl}, used +% within the variable argument of \cs{RespBoxMath}, declares a multi-letter variable. There are +% two styles, one an extension of the other: (1) |\rpl{alpha}{x}|, declares that the multi-letter +% variable `\texttt{alpha}' is the same as the usual single variable `\texttt{x}'; (2) |\rpl{alpha->\\u03B1}{x}| declare +% the variable `\texttt{alpha}' to be the same as `\texttt{x}', it also says to use |\\u0381| as the +% format appearance of `\texttt{alpha}'. +% \changes{v7.9a}{2017/08/05}{Added \string\cs{eq@rpl} to support multi-letter variables} +% \begin{macrocode} +\def\eq@rpl#1#2{_rplVarsBy('#1','#2')@} % dps17 +% \end{macrocode} +% A variation on the objective style math problem, is to initially populate the response box with an +% incorrect answer and ask the student to correct it. (Good for future teachers.) The problem type set +% straightforward when multi-variables are not used, just specify the \cs{V} and \cs{DV} keys in the +% optional argument of \cs{RespBoxMath}. When multi-variables are used, we have to precede the question +% with \DescribeMacro{\setInitAltAppr}\cs{setInitAltAppr}. There are two variations, the first is for +% a non-\app{dvips/Distiller} workflow (document JavaScript are embedded at the creation of the PDF; +% the second variation is with Distiller, where the document JavaScript is embedded with \app{Acrobat} +% after the creation of the PDF. In the latter case, the JavaScript functions used below (\texttt{processMathVars}, +% \texttt{getSubstValue}, and \texttt{RespBoxAppr} are not available yet when the document is initially +% opened in \app{Acrobat}. As a result, an exception is thrown. When the exception is thrown, +% \texttt{app.setTimeOut} gives a delay and the field is reset after 25 milliseconds, this causes +% the \emph{initial} alternate appearance to appear, if that is desired. +% \changes{v8.1a}{2017/09/03}{Add \string\cs{setInitAltAppr} for setting the initial alternate appearance} +% \begin{macrocode} +\ifnum\eq@drivernum=0\def\RorRT{\r\t}\else\def\RorRT{\r}\fi +\def\toAltApprCnt{0}\def\toAltApprVar{_toAltAppr\toAltApprCnt} +\def\toAltApprCntInc{{\@tempcnta=\toAltApprCnt\relax + \advance\@tempcnta1\relax + \xdef\toAltApprCnt{\the\@tempcnta}}} +\def\setCoreInitAltAppr{% + var\eqSP_substVars=\indepVars;\RorRT + var\eqSP_mathVars=processMathVars(_substVars);\RorRT + var\eqSP_substValue=getSubstValue(_substVars,event.value);\RorRT + event.value=RespBoxAppr(event);\RorRT + getSubstValue.aSubsts=[];% +} +\def\bInitAltAppr{\ifShowAppr + \def\ShowApprSAVE{true}\toAltApprCntInc\ShowApprfalse + \def\eqAddAAFormat{\ifnum\eq@drivernum=0try\eqLBr\RorRT\fi + \setCoreInitAltAppr\ifnum\eq@drivernum=0 \r\eqRBr catch(e){\RorRT + var\eqSP\toAltApprVar=% + app.setTimeOut('this.resetForm("'+event.target.name+'");% + app.clearTimeOut(\toAltApprVar);',250);\r}\fi}\else + \def\ShowApprSAVE{false}\fi +} +\def\eInitAltAppr{\@nameuse{ShowAppr\ShowApprSAVE}% + \ifShowAppr\altApprOn\let\eqAddAAFormat\@empty\fi} % \end{macrocode} % Get any changes in the appearance of the text box % \changes{v6.4c}{2011/07/01}{\cs{RespBoxMath} now records its lists of % independent variables under the global variable \texttt{\_mathVars}.} % \begin{macrocode} -\begin{defineJS}[% - \catcode`\%=14\relax\catcode`\@=0\relax]{\AAKqRespBoxMath} -if(event.willCommit){ - RecordPointValue(@eqPTs,@thequestionno@ifx@grpquestions1,% -@thegrpquestionno,@grpPointValue,@grpTotalWeight,% -"@grpEvalFunction"@fi); - RecordProblemType("@eqQT",@thequestionno); - _mathVars=@indepVar; - var retn = @processJSfunc(@rbArgs,@compareJSfunc); - ProcUserResp(retn,event.value,@thequestionno,% -0@ifx@grpquestions1,@thegrpquestionno@fi); -} -if (!isQuizInitialized("@currQuiz")) { - @eqObjAlert@space eqAppAlert(InitMsg("@bqlabelISO"),3); - event.rc = false; +\def\AAKqRespBoxMath{% +% \end{macrocode} +% \cs{AAKqRespBoxMath} is the default keystroke action script for \cs{RespBoxMath} +% \begin{macrocode} + if(event.willCommit){\r\t + RecordPointValue(\eqPTs,\thequestionno\ifx\grpquestions1,% +\thegrpquestionno,\grpPointValue,\grpTotalWeight,% +"\grpEvalFunction"\fi);\r\t + RecordProblemType("\eqQT",\thequestionno);\r\t +% \end{macrocode} +% If there are substitute variables, \cs{ifSubstVars} is true, and the script below +% are the lines developed in support of multi-letter variables. +% \begin{macrocode} +\ifSubstVars % dps17 + var\eqSP_substVars=\indepVars;\r\t + var\eqSP_mathVars=processMathVars(_substVars);\r\t + var\eqSP_substValue=getSubstValue(_substVars,event.value);\r\t + var\eqSP_substAns=getSubstValue(_substVars,"\eqCorrectAns");\r\t + var\eqSP retn=\processJSfunc(\rbArgs,% + \compareJSfunc,_substValue);\r\t +\else + var\eqSP_mathVars=\indepVars;\r\t + var\eqSP retn=\processJSfunc(\rbArgs,\compareJSfunc);\r\t +\fi + ProcUserResp(retn,event.value,\thequestionno,% +0\ifx\grpquestions1,\thegrpquestionno\fi);\r + }\r + if (!isQuizInitialized("\currQuiz")) {\r\t + \eqObjAlert\space eqAppAlert(InitMsg("\bqlabelISO"),3);\r\t + event.rc = false;\r + } } -\end{defineJS} \def\RespBoxMathDefaults {% \BC{0 0 0}\S{S}\textColor{0 g}\F{\FPrint}\W{1} @@ -7571,88 +7825,122 @@ if (!isQuizInitialized("@currQuiz")) { \else\noexpand\Ff{\FfReadOnly}\fi\fi\fi }% } -\let\eqFormatArg\@empty -\def\@@RespBoxMathActions -{% - \AA{\if\eqQuizType\isQZ - \AAKeystroke{\AAKqRespBoxMath\eqAAKeystrokeArg} - \AAFormat{\eqFormatArg} - \else - \AAKeystroke{if(event.willCommit) {\r\t - _mathVars=\indepVar;\r\t - retn=\processJSfunc(\rbArgs,\compareJSfunc);\r -\if\@sqTurnOffAlerts1 - \t OnBlurRespBox(% - \if\@sqTurnOffAlerts1retn\else null\fi,"\curr@quiz"); - \eqAAKeystrokeArg\r +\let\eqAddAAFormat\@empty +% \end{macrocode} +% \DescribeMacro{\eqSP}\cs{eqSP} is a space character to keep \textsf{dvips} from breaking lines at space. +% \begin{macrocode} +\def\eqSP{\string\040} % dps17 +\def\eqLBr{\string\173} +\def\eqRBr{\string\175} +\def\@@RespBoxMathActions{% + \AA{\if\eqQuizType\isQZ + \AAKeystroke{\AAKqRespBoxMath\eqAddAAKeystroke} + \AAFormat{\ifShowAppr\ifSubstVars\ifarrowDelim % dps17 +% \end{macrocode} +% The \texttt{RespBoxApp()} JavaScript function replaces the multi-letter variable (\texttt{alpha}, for example) +% with its appearance (|\\u03B1|, eg). +% \begin{macrocode} + try{event.value=RespBoxAppr(event);}catch(e){}\r + \fi\fi\fi\eqAddAAFormat} + \else + \AAKeystroke{if(event.willCommit) {\r\t +\ifSubstVars% +% \end{macrocode} +% If there are multi-letter variables (\cs{SubstVarstrue}), we insert the code developed. +% \begin{macrocode} + var\eqSP_substVars=\indepVars;\r\t + var\eqSP_mathVars=processMathVars(_substVars);\r\t + var\eqSP_substValue=getSubstValue(_substVars,event.value);\r\t + var\eqSP_substAns=getSubstValue(_substVars,"\eqCorrectAns");\r\t + var\eqSP retn=\processJSfunc(\rbArgs,% + \compareJSfunc,_substValue);\r\t +\else + var\eqSP_mathVars=\indepVars;\r\t + var\eqSP retn=\processJSfunc(\rbArgs,\compareJSfunc); \fi - }% - } - \AAFormat{\eqFormatArg}% - \AAOnFocus{\JS{var retn = null;}}% - \AAOnBlur{\JS{OnBlurRespBox(null,"\curr@quiz");}}% - \fi - } +\if\@sqTurnOffAlerts1\r\t + OnBlurRespBox(retn,"\curr@quiz"); +\fi +% \end{macrocode} +% Moved \cs{eqAAKeystrokArg} from the conditional to the position below. +% \changes{v7.8i}{2017/07/21}{Moved \string\cs{eqAAKeystrokArg}} +% \begin{macrocode} + \eqAddAAKeystroke\r + }} + \AAFormat{\ifShowAppr\ifSubstVars\ifarrowDelim % dps17 + try{event.value=RespBoxAppr(event);}catch(e){}\r\fi\fi\fi + \eqAddAAFormat}% + \AAOnFocus{\JS{var retn = null;}}% + \AAOnBlur{\JS{OnBlurRespBox(null,"\curr@quiz");}}% +\fi + } } +\def\annot@subtype@rbm{rbm} \newcommand\@RespBox[1][] {% - \eq@AddProbToQzQuesList - \smallskip\ifx\grpquestions\eq@Zero - \addtocounter{eqpointvalue}{\eqPTs}\fi - \if\eqQuizType\isQZ - \def\rbFlag{1}\global\IsRespBoxtrue - \ifx\grpquestions\eq@One - \stepcounter{grpquestionno}% - \def\Fld@name{% - grpobj.\curr@quiz.\thequestionno.\thegrpquestionno}% - \else - \eq@recordThesePTs\eq@recordProbType - \edef\eqtmp{\aPointType}% - \xdef\aPointType{\eqtmp,[\eqPTs,"math"]}% - \stepcounter{questionno}% - \def\Fld@name{obj.\curr@quiz.\thequestionno}% - \fi - \else % shortquiz - \ifx\grpquestions\eq@One - \stepcounter{grpquestionno}% - \def\Fld@name{% - grpobj.\oField.\thequestionno.\thegrpquestionno}% - \else - \stepcounter{questionno}% - \def\Fld@name{% - obj.\oField.\thequestionno}% - \fi + \edef\annot@subtype{\annot@subtype@rbm}% + \eq@AddProbToQzQuesList + \smallskip\ifx\grpquestions\eq@Zero + \addtocounter{eqpointvalue}{\eqPTs}\fi + \if\eqQuizType\isQZ + \def\rbFlag{1}\global\IsRespBoxtrue + \ifx\grpquestions\eq@One + \stepcounter{grpquestionno}% + \def\Fld@name{% + grpobj.\curr@quiz.\thequestionno.\thegrpquestionno}% + \else + \eq@recordThesePTs\eq@recordProbType + \edef\eqtmp{\aPointType}% + \xdef\aPointType{\eqtmp,[\eqPTs,"math"]}% + \stepcounter{questionno}% + \def\Fld@name{obj.\curr@quiz.\thequestionno}% + \fi + \else % shortquiz + \ifx\grpquestions\eq@One + \stepcounter{grpquestionno}% + \def\Fld@name{% + grpobj.\oField.\thequestionno.\thegrpquestionno}% + \else + \stepcounter{questionno}% + \def\Fld@name{% + obj.\oField.\thequestionno}% \fi + \fi % \end{macrocode} % Changed (v6.3f, 2008/10/08) the command \cs{array} to \cs{Array} to avoid clashing with the % array command defined in \texttt{amsmath}. % \begin{macrocode} - \let\Array\aeb@array - \moreRespBoxMathDefaults + \let\Array\aeb@array + \moreRespBoxMathDefaults % \end{macrocode} % (2014/01/23) This is tricky, I'm enclosing \cs{text@@Field} in an \cs{mbox}, beginning here % \begin{macrocode} - \leavevmode\hbox\bgroup\text@@Field{#1}{\Fld@name}% - {\RBW}{\DefaultHeightOfWidget}% - {\eq@protect\AA}{\eq@setWidgetProps\eq@RespBox}% - {\RespBoxMathDefaults\@moreRespBoxMathDefaults - \@@RespBoxMathActions\every@eqTextField\every@RespBoxMath}% + \leavevmode\hbox\bgroup\let\rpl\eq@rpl + \text@@Field{#1}{\Fld@name}% + {\RBW}{\DefaultHeightOfWidget}% + {\eq@protect\AA}{\eq@setWidgetProps\eq@RespBox}% + {\RespBoxMathDefaults\@moreRespBoxMathDefaults + \@@RespBoxMathActions\every@eqTextField\every@RespBoxMath}% } % \end{macrocode} % Get the second parameter, which is the correct answer to the question, and % test to see if there is a specification for the optional third parameter, % which is the variable list, `\texttt x' is the default. +% \changes{v8.1}{2017/09/02}{Sanitize superscript before \string\cs{pdfstringdef} is applied} +% \changes{v8.1c}{2017/09/30}{Define \string\cs{eqCorrectAnsTeX} to display the answer +% in preview mode.} % \begin{macrocode} -\def\eq@RespBox#1{\gdef\eqCorrectAns{#1}\if\grpquestions\eq@Zero +\def\eq@RespBox#1{\pdfstringdef\eqCorrectAns{#1}% + \gdef\eqCorrectAnsTeX{#1}\if\grpquestions\eq@Zero % \end{macrocode} % If not within a \texttt{mathGrp} environment, if within a MCFI command pair we save the author's % answer as \cs{s@veCorrAnsMCFI}; otherwise, we record the author's answer. If within % \texttt{mathGrp} environment, we record is as part of the group array to be use later. % \begin{macrocode} - \ifwithinMCFI\gdef\s@veCorrAnsMCFI{"#1"}\else -% \eq@recordCorrAns{"#1"} -\fi\else\eq@recordGrpAnsArray{"#1"}\fi - \@ifnextchar({\@eq@RespBox{#1}}{\@eq@RespBox{#1}(x)}} + \ifwithinMCFI\gdef\s@veCorrAnsMCFI{"#1"}\fi + \else + \eq@recordGrpAnsArray{"#1"}\fi + \@ifnextchar({\@eq@RespBox{#1}}{\@eq@RespBox{#1}(x)}} % \end{macrocode} % Pick up the optional third parameter, then test whether the optional fourth parameter is there. % There are two forms: the [mydest] an explicit destination for the solution to the problem, or @@ -7660,8 +7948,8 @@ if (!isQuizInitialized("@currQuiz")) { % \texttt{[\string\curr@quiz.\string\thequestionno]}. % \begin{macrocode} \def\@eq@RespBox#1(#2){\@ifnextchar[{\@eq@RespB@x{#1}(#2)}% - {\@ifstar{\@eq@RespB@x{#1}(#2)[\curr@quiz.\thequestionno]}% - {\@eq@RespB@x{#1}(#2)[]}}} + {\@ifstar{\@eq@RespB@x{#1}(#2)[\curr@quiz.\thequestionno]}% + {\@eq@RespB@x{#1}(#2)[]}}} % \end{macrocode} % Now get the next three parameters: the number of samples, the precision, and the first of the % two interval parameters. @@ -7676,18 +7964,172 @@ if (!isQuizInitialized("@currQuiz")) { % \cs{eq@defaultRDPrecision} which can be set by \cs{defaultRDPrecision}. The default definition % is \verb!\defaultRDPrecision{1E-14}!. % \begin{macrocode} -\def\@eq@RespB@x#1(#2)[#3]#4#5#6{\xdef\@qzsolndest{#3}% - \def\indepVar{"#2"}\def\eq@precision{#5}% +\newif\ifarrowDelim\arrowDelimfalse % dps17 +% \end{macrocode} +% The problem is to detect when \cs{indepVars} contains the arrow notation (\verb~->~), this signals +% that the appearance of the user's response is to be replaced by another appearance. The command +% \cs{GiiRpli} attempts to do just that, it sets \cs{arrowDelim} to true if an arrow is detectect, +% otherwise, to false. +% \begin{macrocode} +\def\rpl@#1#2{\rpl@i#1->\@nil} +\def\rpl@i#1->#2\@nil{\def\argii{#2}\ifx\argii\@empty\else + \global\arrowDelimtrue\fi} +\def\GiiRpli#1{\global\arrowDelimfalse\GiiRplii#1\rpl{}{}\@nil} +\def\GiiRplii#1\rpl#2#3#4\@nil{\def\argiv{#4}% + \ifx\argiv\@empty\let\eq@next\relax\else + \rpl@{#2}{#3}\ifarrowDelim\let\eq@next\relax\else + \def\eq@next{\GiiRplii#4\@nil}\fi\fi + \eq@next} +% \end{macrocode} +% \textbf{Is arrow specified?} \cs{isAltApprSpec} determines whether the delimiter `\texttt{->}' is present, if it is +% we set |\global\arrowDelimtrue|, otherwise it is globally set to false. Its supporting +% code is listed above: \cs{rpl@} and \cs{GiiRpli} +% \begin{macrocode} +\def\isAltApprSpec#1{\bgroup\if\frstIsrpl\eq@YES\GiiRpli{#1}\else + \expandafter\GiiRpli\expandafter{#1}\fi\egroup} % dps17 +% \end{macrocode} +% If the independent variables are passed as a command, we need +% to expand first; on the other hand, if the argument is literal and begins with \cs{rpl} +% we do not expand first. This is to get a correct determination of \cs{ifSubstVars} +% and \cs{ifarrowDelim}. +% \begin{macrocode} +\def\isFrstrpl#1#2\@nil{\ifx#1\rpl\let\frstIsrpl\eq@YES\else + \let\frstIsrpl\eq@NO\fi} +% \end{macrocode} +% Macros to count the number of independent variables +% \begin{macrocode} +\def\cntComm@s#1{\@tempcnta\z@\expandafter\cntComm@si#1,,\@nil} +\def\cntComm@si#1,#2,\@nil{\def\argii{#2}\ifx\argii\@empty + \def\eq@next{\edef\nC{\the\@tempcnta}}\else + \advance\@tempcnta\@ne\def\eq@next{\cntComm@si#2,\@nil}\fi + \eq@next}\def\eq@SC{;}\def\rplSofT#1#2{#2} +\def\cntVars#1{\let\rpl\rplSofT\edef\eV@rs{#1}\let\rpl\eq@rpl + \cntComm@s{\eV@rs}\ifnum\nC>\z@ + \@tempcnta\nC\relax\advance\@tempcnta\@ne + \xdef\nV{\the\@tempcnta}\else\@tempcnta\z@ + \expandafter\cntVarsi\eV@rs;\@nil\fi} + \def\cntVarsi#1#2\@nil{\def\argii{#2}% + \ifx\argii\eq@SC\def\eq@next{\advance\@tempcnta\@ne + \edef\nV{\the\@tempcnta}}\else\advance\@tempcnta\@ne + \def\eq@next{\cntVarsi#2\@nil}\fi + \eq@next} +\def\eq@X{x} +% \end{macrocode} +% It there repetition? (\texttt{[0,1]*3}, eg) +% \begin{macrocode} +\def\eq@isThereRept#1{\let\eq@isRept\eq@Zero\expandafter + \eq@isThereRepti#1*\@nil} +\def\eq@isThereRepti#1*#2\@nil{\def\argii{#2}\ifx\argii\@empty + \let\eq@isRept\eq@Zero\else\let\eq@isRept\eq@One\fi} +% \end{macrocode} +% Expand repetition if present (\texttt{[0,1]*3=[0,1]x[0,1]x[0,1]}, eg) +% \begin{macrocode} +\def\eq@obeyReptOfIntrvls#1{% + \expandafter\eq@isThereRept\expandafter{#1}% sets \eq@isRept + \if\eq@isRept\eq@Zero\relax\let\eq@interv@ls\@empty\expandafter + \g@addto@macro\expandafter\eq@interv@ls + \expandafter{#1}\let\eq@next\relax\else\let\eq@interv@ls\@gobble + \def\eq@next{\expandafter + \eq@obeyReptOfIntrvlsi#1x[]x\@nil}\fi\eq@next} +\def\eq@obeyReptOfIntrvlsi#1[#2]#3#4x#5\@nil{% + \def\argi{#2}\def\argii{#3}\def\argiv{#5}% + \ifx\argi\@empty\let\eq@next\relax\else + \ifx\argii\eq@X\g@addto@macro\eq@interv@ls{x[#2]}% + \def\eq@next{\eq@obeyReptOfIntrvlsi#4x#5x\@nil}\else + % repetition of an interval + \eq@ddtorepIntrvl{[#2]}{#4}% + \def\eq@next{\eq@obeyReptOfIntrvlsi#5x\@nil}\fi + \fi + \eq@next +} +\def\eq@ddtorepIntrvl#1#2{\@tempcnta=#2 \eq@ddtorepIntrvli{#1}{#2}} +\def\eq@ddtorepIntrvli#1#2{\@whilenum\@tempcnta>\z@\do + {\g@addto@macro\eq@interv@ls{x#1}\advance\@tempcnta\m@ne}} +% \end{macrocode} +% Macros to count the number of intervals. First determine if there +% are repetitions if so, expand them \cs{eq@obeyReptOfIntrvls} returns +% the expanded intervals in \cs{eq@interv@ls} +% \begin{macrocode} +\def\cntIv@ls#1{\@tempcnta\z@\expandafter\cntIv@lsi#1xxx\@nil}% +% \end{macrocode} +% Before counting the intervals, determine if there is repetition, if so +% expand those intervals appropriately. +% \begin{macrocode} +\def\cntIv@lsi#1x#2x\@nil{\def\argii{#2}\ifx\argii\eq@X + \advance\@tempcnta\@ne + \edef\nI{\the\@tempcnta}\let\eq@next\relax\else + \advance\@tempcnta\@ne\def\eq@next{\cntIv@lsi#2x\@nil}\fi +\eq@next} +% \end{macrocode} +% A interval specification might have an intersection in it (\texttt{\&}, so for the purpose +% of counting, we count the intervals up to the first ampersand. +% \changes{v8.1b}{2017/09/06}{Fixed a problem with the use of \string\cs{RespBoxMath} +% when it is within a tabular environment.} +% \begin{macrocode} +\begingroup\@makeother\& +\gdef\eq@ProcIntrvls#1{\expandafter + \eq@ProcIntrvlsi#1&&\@nil} +\gdef\eq@ProcIntrvlsi#1\@nil{\def\argii{#2}% + \ifx\argii\@empty +% \end{macrocode} +% The intervals do not contain an ampersand. +% Expand intervals, if necessary result returns in \cs{eq@interv@ls} +% \begin{macrocode} + \eq@obeyReptOfIntrvls{#1}% +% \end{macrocode} +% Count the intervals +% \begin{macrocode} + \cntIv@ls{\eq@interv@ls}% + \else +% \end{macrocode} +% The intervals contain an ampersand (union of two intervals of equal dimension assumed, +% \meta{interval${}_1$}\texttt{\&}\meta{interval${}_1$}). +% Expand the first set of union. +% \begin{macrocode} + \eq@obeyReptOfIntrvls{#1}% +% \end{macrocode} +% Save this result in \cs{interv@ls} +% \begin{macrocode} + \edef\interv@ls{\eq@interv@ls}% + \cntIv@ls{\eq@interv@ls}% +% \end{macrocode} +% Expand the second set of union +% \begin{macrocode} + \eq@obeyReptOfIntrvls{#2}% + \edef\eq@interv@ls{\interv@ls&\eq@interv@ls}% + \fi +} +\endgroup +% \end{macrocode} +% \cs{RespBoxMath} continues here +% \begin{macrocode} +\def\@eq@RespB@x#1(#2)[#3]#4#5#6{\xdef\@qzsolndest{#3}% dps17 + \gdef\indepVars{"#2"}\isFrstrpl#2\@nil\if\frstIsrpl\eq@YES + \def\@IVi{#2}\else\expandafter\def\expandafter + \@IVi\expandafter{#2}\fi\edef\@IVii{#2}\ifx\@IVi\@IVii +% \end{macrocode} +% If \cs{indepVars} (\texttt{\#2}) does not contain \cs{rpl}, the two versions +% of \cs{@IVi} and \cs{@IVii} should compare favorably. If they differ, the difference +% is due to the presence of \cs{rpl}. +% \begin{macrocode} + \global\SubstVarsfalse\else\global\SubstVarstrue + \isAltApprSpec{#2}\fi +% \end{macrocode} +% \textbf{Counting number of variables.} We count the number of independent variables. +% \begin{macrocode} + \cntVars{#2}\def\eq@precision{#5}% \ifx\eq@precision\eq@ZERO \def\eq@defaultCompare{reldiffCompare}% % \end{macrocode} % (2017/01/11) Replace \texttt{\#1} by \cs{eqCorrectAns} to delay expansion % \changes{v7.8d}{2017/01/11}{Replace \string\texttt{\#1} by \string\cs{eqCorrectAns} to delay expansion} % \begin{macrocode} - \def\rbArgstmp{% - \rbFlag,"\eqCorrectAns",#4,\eq@defaultRDPrecision}\else - \def\eq@defaultCompare{diffCompare}% - \def\rbArgstmp{\rbFlag,"\eqCorrectAns",#4,#5}\fi + \def\rbArgstmp{\rbFlag,% dps17 + \ifSubstVars_substAns\else"#1"\fi,#4,% + \eq@defaultRDPrecision}\else + \def\eq@defaultCompare{diffCompare}% + \def\rbArgstmp{\rbFlag,% dps17 + \ifSubstVars_substAns\else"#1"\fi,#4,#5}\fi % \end{macrocode} % We have arrived at the first of possibly two parameters that define the interval(s) % from which to sample random points. There are two forms, the old style (deprecated) @@ -7696,22 +8138,22 @@ if (!isQuizInitialized("@currQuiz")) { % (10/10/11) To support \cs{viidna}, we expand \texttt{\#6} first before passing it % to the command \cs{@checkforInterval}. % \begin{macrocode} - \edef\eq@ixparam{#6}% - \expandafter\@checkforInterval\eq@ixparam\\% + \edef\eq@ixparam{#6}\expandafter\eq@chkivIntrvls\eq@ixparam\\% } % \end{macrocode} % \DescribeMacro{\viidna} is used with the \texttt{satisfyEq} for the seventh parameter, % these routines do not use the ninth, but there needs to be something that does not % stop compilation. % \begin{macrocode} -\def\viidna{[]} +\def\viidna{[0,1]} +%\def\viidna{[]} % \end{macrocode} % If the next token is a `\texttt[', then that signals the beginning of an interval % such as \texttt{[a,b]}, must be the new style. The second parameter is not % needed, and not expected in this case. It would be a mistake to include it. % \begin{macrocode} -\def\@checkforInterval{% - \@ifnextchar[{\@checkforIntervali}{\@checkforIntervalii}} +\def\eq@chkivIntrvls{\@ifnextchar[{\eq@chkivIntrvlsi}% + {\eq@chkivIntrvlsii}} % \end{macrocode} % This is the case of the new style of defining the interval. We insert it into the % arguments list, and continue on to the next stage. @@ -7720,71 +8162,80 @@ if (!isQuizInitialized("@currQuiz")) { % is next to the left bracket. Somehow, the left brace and right brace get absorbed. We do a % work around, and insert a space after the left bracket. % \begin{macrocode} -\def\@checkforIntervali#1\\{% - \def\rbArgs{\rbArgstmp,"#1",\indepVar}% - \@ifnextchar[{\@eq@@RespBox[ \expandafter\@gobble}% - {\@eq@@RespBox[\eq@defaultCompare]}% +\def\eq@chkivIntrvlsi#1\\{\eq@ProcIntrvls{#1}% + \def\rbArgs{\rbArgstmp,"\eq@interv@ls",_mathVars}% dps17 + \@ifnextchar[{\@eq@@RespBox[ \expandafter\@gobble}% + {\@eq@@RespBox[\eq@defaultCompare]}% } % \end{macrocode} % This is assumed to be the old style for defining the interval. In this case, the next -% token is the right-hand endpoint of the interval, we need it. It would be a mistake -% \texttt{not} to include it. We also test for the presence of the optional +% token is the right-hand endpoint of the interval, we need it. We also test for the presence of the optional % of a customized comparison function, parameter \texttt{\#9} % \begin{macrocode} -\def\@checkforIntervalii#1\\#2{% - \def\rbArgs{\rbArgstmp,"[#1,#2]",\indepVar}% - \@ifnextchar[{\@eq@@RespBox}{\@eq@@RespBox[\eq@defaultCompare]}% +\def\eq@chkivIntrvlsii#1\\#2{\def\nI{1}% + \def\rbArgs{\rbArgstmp,"[#1,#2]",_mathVars}% + \@ifnextchar[{\@eq@@RespBox}{\@eq@@RespBox[\eq@defaultCompare]}% } % \end{macrocode} % Finally, we see if there will be a 10th parameter by seeing if `\texttt*' comes % next. We change the catcodes here, so we can have a left and right brace in the -% optional argument \#9. Hope it works. dps 12/30/03 -%\changes{v6.4g}{2011/07/21}{% -% Changing the definition of \cs{@eq@@RespBox}, removing the change -% in \cs{catcode}s. If this causes problems, can restore the -% old definition. -%} -% \begin{macrocode} -%\def\@eq@@RespBox{\begingroup\catcode`\<=1\relax\catcode`\>=2\relax -% \catcode`\{=12\relax\catcode`\}=12\relax\@eq@@@RespBox} -%\def\@eq@@@RespBox[#1]{\endgroup\@ifstar{\jsRespBox[#1]}% -% {\jsRespBox[#1]{ProcResp}}} -% \end{macrocode} -% Below is an alternate (and obvious) definition for \cs{@eq@@RespBox}. Whatever -% reason I had to change the catcodes, I don't remember, and things seem to work -% without it. But, will keep things as they are. +% optional argument \#9. Hope it works. dps 12/30/03\medskip % \begin{macrocode} -\def\@eq@@RespBox{\@eq@@@RespBox} -\def\@eq@@@RespBox[#1]{\@ifstar{\jsRespBox[#1]}% +\def\@eq@@RespBox[#1]{\@ifstar{\jsRespBox[#1]}% {\jsRespBox[#1]{ProcResp}}} \def\eq@ProcRespIntervals{ProcRespIntervals} +\def\eq@ProcRespSetNum{ProcRespSetNum} +\def\eq@ProcRespSetSym{ProcRespSetSym} +\def\eq@ProcRespEvalEq{ProcRespEvalEq} +\def\eq@ProcRespEvalEqNonZero{ProcRespEvalEqNonZero} +\def\eq@ProcRespEvalEqList{ProcRespEvalEqList} +\def\eq@ProcRespEvalEqListNonZero{ProcRespEvalEqListNonZero} \def\jsRespBox[#1]#2{\def\compareJSfunc{#1}% - \def\processJSfunc{#2}\gdef\g@processJSfunc{#2}% 01/11 + \def\processJSfunc{#2}\gdef\g@processJSfunc{#2}% 01/11 + \ifnum\nV=\nI\relax\else + \ifx\processJSfunc\eq@ProcRespSetNum\else + \ifx\processJSfunc\eq@ProcRespSetSym\else + \ifx\processJSfunc\eq@ProcRespEvalEq\else + \ifx\processJSfunc\eq@ProcRespEvalEqNonZero\else + \ifx\processJSfunc\eq@ProcRespEvalEqList\else + \ifx\processJSfunc\eq@ProcRespEvalEqListNonZero\else + \PackageWarning{exerquiz}{The number of variables does not + match\MessageBreak the number of intervals. The + problem\MessageBreak may not evaluate properly}\fi\fi\fi\fi\fi\fi\fi % \end{macrocode} % (2017/01/11) Run answer through \cs{pdfstringdef} if % \texttt{ProcRespIntervals} is used to avoid unbalanced parentheses. % \changes{v7.8d}{2017/01/11}{Run answer through \string\cs{pdfstringdef} if % \string\texttt{ProcRespIntervals} is used.} % \begin{macrocode} - \ifx\eq@ProcRespIntervals\g@processJSfunc + \ifx\eq@ProcRespIntervals\g@processJSfunc % \end{macrocode} % When the response function is \texttt{ProcRespIntervals} there is no `real' math, no subscripts, % no superscripts. We turn of the math mode warning before \cs{pdfstringdef}. % \begin{macrocode} - \let\@inmathwarn@SAVE\@inmathwarn\let\@inmathwarn\@gobble + \let\@inmathwarn@SAVE\@inmathwarn\let\@inmathwarn\@gobble % \end{macrocode} % When the response function is \texttt{ProcRespIntervals}, there may be unbalanced parentheses, we'll % pass \cs{eqCorrectAns} through \cs{pdfstringdef} to escape them. % \begin{macrocode} - \pdfstringdef{\eqCorrectAns}{\eqCorrectAns}% - \let\@inmathwarn\@inmathwarn@SAVE\fi - \eq@recordCorrAns{"\eqCorrectAns"}% 01/11 - \ifeq@proofing\makebox[0pt][l]{\space\math@correctAnswer}\fi - \eq@TextField % send to the driver-dependent macro + \pdfstringdef{\eqCorrectAns}{\eqCorrectAns}% + \let\@inmathwarn\@inmathwarn@SAVE\fi +% \end{macrocode} +% Remove parentheses from the argument of \cs{eq@recordCorrAns}. +% \changes{v8.2}{2018/03/18}{Corrected \string\cs{eq@recordCorrAns}} +% \changes{v8.2.1}{2018/03/19}{If not a math group, record this data} +% \begin{macrocode} +\ifx\grpquestions\eq@Zero + \eq@recordCorrAns{"\eqCorrectAns"}% 2018/03/18 +% \eq@recordCorrAns{("\eqCorrectAns")}% 01/11 +\fi + \ifeq@proofing\makebox[0pt][l]{\space\math@correctAnswer}\fi + \eq@TextField % send to the driver-dependent macro % \end{macrocode} % (2014/01/23) Closing the \cs{hbox} here, begun at the opening of \cs{text@@Field} above. % \begin{macrocode} - \egroup + \egroup % hbox + \endgroup % \RespBoxMath } % \end{macrocode} % The primitive \cs{meaning} is used to get a typeset version of the answer for the \texttt{proofing} @@ -7794,9 +8245,9 @@ if (!isQuizInitialized("@currQuiz")) { % for example, following a period (`.'). Oh, well. % \begin{macrocode} \def\gobbleMacro#1>{} -\gdef\math@correctAnswer{% - \ttfamily\color{\@proofingsymbolColor}\spaceskip=2pt\xspaceskip=2pt% - \expandafter\gobbleMacro\meaning\eqCorrectAns +\gdef\math@correctAnswer{\ttfamily + \color{\@proofingsymbolColor}\spaceskip=2pt\xspaceskip=2pt% + \expandafter\gobbleMacro\meaning\eqCorrectAnsTeX } % \end{macrocode} % \end{macro} @@ -7884,7 +8335,12 @@ if (!isQuizInitialized("@currQuiz")) { \def\@@RespBoxTxtActions {% \AA{\if\eqQuizType\isQZ - \AAKeystroke{\AAKqRespBoxTxt} +% \end{macrocode} +% Added \cs{eqAAKeystrokArg} to \cs{@@RespBoxTxtActions} +% \changes{v7.8i}{2017/07/21}{Added \string\cs{eqAAKeystrokArg} to \string\cs{@@RespBoxTxtActions}} +% \begin{macrocode} + \AAKeystroke{\AAKqRespBoxTxt\eqAddAAKeystroke} + \AAFormat{\eqAddAAFormat} \else \AAKeystroke{% if(event.willCommit) {\r\t @@ -7892,8 +8348,10 @@ if (!isQuizInitialized("@currQuiz")) { \if\@sqTurnOffAlerts1 \t\RespBoxTxtOnBlur\r \fi + \eqAddAAKeystroke\r }% } + \AAFormat{\eqAddAAFormat} \AAOnFocus{\JS{var retn = null;}} % \end{macrocode} % dps 2/12/05 A fix for Acro7.0, a change in the blur event, must @@ -7906,10 +8364,11 @@ if (!isQuizInitialized("@currQuiz")) { \fi } } +\def\annot@subtype@rbt{rbt} \newcommand\@RespBoxTxt[1][] {% + \edef\annot@subtype{\annot@subtype@rbt}% \eq@AddProbToQzQuesList -% \smallskip \ifx\grpquestions\eq@Zero\addtocounter{eqpointvalue}{\eqPTs}\fi \if\eqQuizType\isQZ \def\rbFlag{1}\global\IsRespBoxtrue @@ -8099,8 +8558,10 @@ if (!isQuizInitialized("@currQuiz")) { % Here is the beginning of \cs{RespBoxTxtPC}. % \begin{macrocode} \newcommand{\RespBoxTxtPC}{\def\rbFlag{0}\@RespBoxTxtPC} +\def\annot@subtype@rbtpc{rbtpc} \newcommand\@RespBoxTxtPC[1][] {% + \edef\annot@subtype{\annot@subtype@rbtpc}% \eq@AddProbToQzQuesList \smallskip\ifx\grpquestions\eq@Zero \addtocounter{eqpointvalue}{\eqPTs}\fi @@ -8314,17 +8775,34 @@ if (!isQuizInitialized("@currQuiz")) { \BC{0 0 0}\BG{.7529 .7529 .7529}\H{P} } \def\normalCABtnBC{0 0 0} - \def\qCorrAnsButtonActionHook - {% - \JS{% - \ifx\@qzsolndest\@empty\else - if (event.shift)\jsR\jsT - this.gotoNamedDest("\@qzsolndest");\jsR - else\jsR\jsT - \fi - \processJSfunc("Ans.\curr@quiz","\CorrectAns",\currQuiz); - }% - } +\def\qCorrAnsButtonActionHook{\JS{% +\ifx\@qzsolndest\@empty\else + if (event.shift)\jsR\jsT + this.gotoNamedDest("\@qzsolndest");\jsR + else {\jsR\jsT\fi +% \end{macrocode} +% The script for the \cs{CorrAnsButton} accommodates multi-letter variables +% \begin{macrocode} +\ifShowAppr % dps17 + \ifarrowDelim + if (typeof event.target.appr=="undefined")\r\JST\t + event.target.appr=false;\r\JST + event.target.appr=!event.target.appr;\r\JST + if (event.target.appr) {\r\t\JST + var _substVars=\indepVars;\r\t\JST + var _substAns=getSubstValue(_substVars,"\CorrectAns");\r\t\JST + var value=RespBoxAppr("\CorrectAns");\r\JST + } else value="\CorrectAns";\r\JST + \else + value="\CorrectAns";\r\JST + \fi +\else + value="\CorrectAns";\r\JST +\fi + \processJSfunc("Ans.\curr@quiz",value,\currQuiz);\r +\ifx\@qzsolndest\@empty\else % dps17 + }\fi +}} \def\sqCorrAnsButtonActionHook {% \JS{% @@ -8348,7 +8826,8 @@ if (!isQuizInitialized("@currQuiz")) { \eq@@@CorrAnsButton{#1}{#2}{DisplayAnswer}}% } \def\eq@@@CorrAnsButton#1#2#3{\gdef\CorrectAns{#2}% - \def\processJSfunc{#3}% + \def\processJSfunc{#3}\ifx\@qzsolndest\@empty\let\JST\@empty\else + \let\JST\jsT\fi % dps17 \ifx\eq@ProcRespIntervals\g@processJSfunc % 01/11 \let\@inmathwarn@SAVE\@inmathwarn\let\@inmathwarn\@gobble % \end{macrocode} @@ -8364,8 +8843,9 @@ if (!isQuizInitialized("@currQuiz")) { \ifx\@qzsolndest\@empty%\noexpand\BC{\normalCABtnBC}% \else\noexpand\BC{\solution@Color}\fi \noexpand\A{\noexpand\qCorrAnsButtonActionHook}}% - \ifeq@noquizsolutions\else - \mbox{\push@@Button{#1}{\Fld@name}{}{\DefaultHeightOfWidget}% + \ifeq@noquizsolutions\else % dps17 (\let\rpl\eq@rpl) + \mbox{\let\rpl\eq@rpl + \push@@Button{#1}{\Fld@name}{}{\DefaultHeightOfWidget}% {\eq@protect\A}{\eq@setButtonProps\eq@Button@driver}% {\CorrAnsButtonDefaults\@@CorrAnsButtonActions \every@ButtonField\every@CorrAnsButton}}% @@ -8723,8 +9203,6 @@ if (!isQuizInitialized("@currQuiz")) { % \begin{macrocode} \ifx\grpquestions\eq@Zero\eq@tmpExp\fi } -% \end{macrocode} -% \begin{macrocode} %</package> %<*sumrytbls> % \end{macrocode} @@ -9080,11 +9558,12 @@ if (!isQuizInitialized("@currQuiz")) { % \end{macrocode} % \end{environment} % \begin{macrocode} +% End sumrytbls segment %</sumrytbls> -% \end{macrocde} +%<*mcfi> +% \end{macrocode} % \subsection{Posing MC/math fill-in questions} % \begin{macrocode} -%<*mcfi> \def\bMCFI{% \withinMCFItrue \ifx\qRadionActionsHook\@empty @@ -9141,13 +9620,7 @@ if (!isQuizInitialized("@currQuiz")) { % \begin{macrocode} \inputMCFICode % \end{macrocode} -% \begin{macrocode} -%</package> -% \end{macrocode} % \section{eForms Support} -% \begin{macrocode} -%<*package> -% \end{macrocode} % \begin{macro}{\solutionColor} % This color is introduced at the pdfmark/rawPDF level. Define % the color without commas. For example |\solutionColor{0 .6 0}| @@ -9159,8 +9632,8 @@ if (!isQuizInitialized("@currQuiz")) { \solutionColor{\solutionColorDef} % \end{macrocode} % \end{macro} -% % \begin{macrocode} +% End of package segment %</package> %<*eqcolor> % \end{macrocode} @@ -9404,48 +9877,6 @@ if (!isQuizInitialized("@currQuiz")) { \newcommand\everyGradeField[1]{\def\every@GradeField{#1}} \def\every@GradeField{} % \end{macrocode} -% \begin{macro}{\AddAAFormat} -% Here is the definition of \cs{AddAAFormat}. This macro can be used -% in \cs{RespBoxMath} to add in formatting of the answer. This macro is -% necessary because the \cs{AA} actions for the \textsf{exerquiz} quiz macros -% are ``protected''; the document author cannot accidentally overwrite my -% JavaScript for processing the user's answer. -% \begin{flushleft} -% Example: In the preamble -%\begin{verbatim} -%\begin{defineJS}{\formatAsSet} -%if (event.value.replace(/\\s/g,"") != "") -% event.value = "{ " + event.value + " }"; -%\end{defineJS} -%\end{verbatim} -% and in the body of a \texttt{quiz} environment, -%\begin{verbatim} -%$x^2 - 3x + 2 = 0$, $S = \RespBoxMath[\AddAAFormat{\formatAsSet} -% \rectW{.75in}\textSize{0}]{1,2}{1}{.0001}{[0,1]}*{ProcRespSetNum}$ -%\end{verbatim} -%\end{flushleft} -% \begin{macrocode} -\def\@eqAddAAFormat#1{\def\eqFormatArg{#1}} -\def\eq@AddAAFormat{} -\def\formatAsSet{try{formatAsSet()}catch(e){}} -\def\formatAsVector{try{formatAsVector()}catch(e){}} -% \end{macrocode} -% \end{macro} -% \begin{macro}{\AddAAKeystroke} -% The value of this key is JS code that executes after the input box has been processed. -% Created to use with AcroFleX for showing graphs after the user enters a response. -% -%\changes{v6.3b}{2008/06/29} -%{ -% Added the \cs{AddAAKeystroke} to the recognizable set of keys. This will be obeyed -% within the optional arguments of \cs{RespBoxMath}. -%} -% \begin{macrocode} -\def\@eqAddAAKeystroke#1{\def\argi{#1}\ifx\argi\@empty - \def\eqAAKeystrokeArg{}\else\def\eqAAKeystrokeArg{\r #1}\fi} -\def\eqAAKeystrokeArg{} -% \end{macrocode} -% \end{macro} % \begin{macro}{\everysqRadioButton} % \begin{macro}{\everyqRadioButton} % Here, you can control the appearance of all the standard checkboxes, also @@ -9496,11 +9927,150 @@ if (!isQuizInitialized("@currQuiz")) { % Replace everyeqGenButten with everyPushButton \let\everyeqGenButton\everyPushButton \let\every@eqGenButton\every@PushButton +\let\eqGenButton\pushButton \newcommand\everyeqIcon[1]{\def\every@eqIcon{#1}} \def\every@eqIcon{} -% dps new -\let\eqGenButton\pushButton % \end{macrocode} +% +% \subsection{Additional Format and Action keys} +% +% \begin{macro}{\AddAAFormat} +% Here is the definition of \cs{AddAAFormat}. This macro can be used +% in \cs{RespBoxMath} to add in formatting of the answer. This macro is +% necessary because the \cs{AA} actions for the \textsf{exerquiz} quiz macros +% are ``protected''; the document author cannot accidentally overwrite my +% JavaScript for processing the user's answer. +% \begin{flushleft} +% Example: In the preamble +%\begin{verbatim} +%\begin{defineJS}{\formatAsSet} +%if (event.value.replace(/\\s/g,"") != "") +% event.value = "{ " + event.value + " }"; +%\end{defineJS} +%\end{verbatim} +% and in the body of a \texttt{quiz} environment, +%\begin{verbatim} +%$x^2 - 3x + 2 = 0$, $S = \RespBoxMath[\AddAAFormat{\formatAsSet} +% \rectW{.75in}\textSize{0}]{1,2}{1}{.0001}{[0,1]}*{ProcRespSetNum}$ +%\end{verbatim} +%\end{flushleft} +% Define a special value (\cs{formatInitAltApprs}) for \cs{AddAAFormat} used in initializing \cs{RespBoxMath} problems, +% where there are alternate appearances. +% \changes{v8.1a}{2017/09/03}{Define a special value (\string\cs{formatInitAltApprs}) for \string\cs{AddAAFormat}} +% \begin{macrocode} +\def\formatInitAltApprs{\formatInitAltApprs} +\def\@eqAddAAFormat#1{\def\@rgi{#1}\ifx\@rgi\formatInitAltApprs + \bInitAltAppr\else\def\eqAddAAFormat{#1}\fi} +\def\eqAddAAFormat{} +\def\formatAsSet{try{formatAsSet()}catch(e){}} +\def\formatAsVector{try{formatAsVector()}catch(e){}} +% \end{macrocode} +% \end{macro} +% What follows are a series of three ``action'' keys, that is, their arguments are +% JavaScript code. They are meant to be used in highly specialized settings. +% \begin{macro}{\setActionKeys} +% The action keys can be set through the optional argument, if available, or they can be set +% globally using the command \cs{setActionKeys}. The only keys supported for use +% as the argument of \cs{setActionKeys} are \cs{AddAAKeystroke\{\meta{code}\}}, +% \cs{AddAAMouseUpMC\{\meta{code}\}}, and \cs{AddAAMouseUpMS\{\meta{code}\}}, though +% this is not enforced due to the obscure nature their use. The action settings remain +% in force until you cancel them out with \cs{AddAAKeystroke\{\}}, for example. +% \changes{v7.8k}{2017/07/22}{Added \string\cs{setActionKeys}} +% \changes{v7.8j}{2017/07/23}{Restricted the use of \string\cs{setActionKeys} to a +% selected number of keys} +% \begin{macrocode} +\def\eq@SupActnLst{{\AddAAKeystroke}{\AddAAMouseUpMC}% + {\AddAAMouseUpMS}{\AddAAFormat}} +\newcommand\setActionKeys{\edef\catOfAt{\the\catcode`@}% + \ifnum\catOfAt=11 \let\eq@CatTail\relax\else + \makeatletter\let\eq@CatTail\makeatother\fi\setActionKeysi} +\def\setActionKeysi#1{\let\eq@itsGood\eq@One + \def\setActionKeys@cont{\processAppArgs#1\end\@nil}% + \begingroup\eq@checkivValidKeys#1\end\ef@nil\endgroup\eq@CatTail} +\def\eq@checkivValidKeys#1#2{\def\eq@GOOD{good}\expandafter + \@tfor\expandafter + \@ction\expandafter:\expandafter=\eq@SupActnLst\do{% + \expandafter\def\@ction{good}}% + \ifx\end#1% if #1=\end, #2=\ef@nil. + \def\eq@next{\aftergroup\setActionKeys@cont}% + \else + \if\eq@itsGood\eq@One + \let\itp@ss0\let\@@next\relax + \expandafter\@tfor\expandafter + \@ction\expandafter:\expandafter=\eq@SupActnLst\do{% + \expandafter\ifx\expandafter#1\@ction + \let\itp@ss\eq@One\@break@tfor + \fi}% do + \if\itp@ss\eq@Zero\let\eq@itsGood\eq@Zero + \def\eq@next{\def\eq@lastArg{#1}\expandafter + \eq@sqkErrorMsg\ef@gobbletonil}\else + \let\eq@next\eq@checkivValidKeys\fi + \else\let\eq@next\ef@gobbletonil\fi + \fi %\ifx\end + \eq@next +} +\def\eq@sqkErrorMsg#1{\PackageError{exerquiz}{The key \expandafter + \string\eq@lastArg\space is not supported by + \string\setActionKeys.\MessageBreak + Remove the key or correct the spelling of the key}{}} +% \end{macrocode} +% The \DescribeMacro{\addToAction}\cs{addToAction} is a companion to \cs{setActionKeys}. When +% \cs{setActionKeys} sets a key, later in the document, you might want to add to that action +% earlier defined. Thus, \verb~\addToAction{\AddAAFormat}{var x=2;}~ appends +% \texttt{var x=2;} to the code already defined earlier by +% \cs{setActionKeys}, I hope. The first argument is one of the keys in \cs{eq@SupActnLst} +% (the only ones accepted), the second argument is the script to add to the previously added script. +% The optional \texttt{*}-argument reverses the order the code is arranged. +% \begin{macrocode} +\def\addToAction{\makeatletter\@ifstar{\let\isSt@r\eq@YES\@ddToAction} + {\let\isSt@r\eq@NO\@ddToAction}} +\def\@ddToAction#1#2{\let\eq@itsGood\eq@One + \def\setActionKeys@cont{\@@ddToAction{#1}{#2}}\begingroup + \eq@checkivValidKeys{#1}{#2}\end\ef@nil\endgroup\makeatother} +\def\@@ddToAction#1#2{\@getCmdName{#1}% + \if\isSt@r\eq@YES\toks2={#2}% + \toks@=\aeb@exiii{\csname eq\@CmdName\endcsname}% + \edef\tmp@tokshold{\the\toks2 \the\toks@}% + \toks@=\expandafter{\tmp@tokshold}\else + \toks@=\aeb@exiii{\csname eq\@CmdName\endcsname#2}\fi + \expandafter\edef\csname eq\@CmdName\endcsname{\the\toks@}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\AddAAKeystroke} +% The value of this key is JS code that executes after the input box has been processed. +% Created to use with AcroFleX for showing graphs after the user enters a response. +% +%\changes{v6.3b}{2008/06/29} +%{ +% Added the \cs{AddAAKeystroke} to the recognizable set of keys. This will be obeyed +% within the optional arguments of \cs{RespBoxMath} and \cs{RespBoxTxt}. +%} +% \begin{macrocode} +\def\@eqAddAAKeystroke#1{\def\argi{#1}\ifx\argi\@empty + \def\eqAddAAKeystroke{}\else\def\eqAddAAKeystroke{#1}\fi} %\r +\def\eqAddAAKeystroke{} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\AddAAMouseUpMC} +% \begin{macro}{\AddAAMouseUpMS} +% Added form keys (for MC and MS questions), can be use to add additional +% action with a mouse up event. +% \changes{v7.8j}{2017/07/21}{Added form keys \string\cs{@eqAddAAMouseUpMC} +% and \string\cs{@eqAddAAMouseUpMS}} +% \begin{macrocode} +\def\@eqAddAAMouseUpMC#1{\def\argi{#1}\ifx\argi\@empty + \def\eqAddAAMouseUpMC{}\else\def\eqAddAAMouseUpMC{#1}\fi} +\def\eqAddAAMouseUpMC{} +\def\@eqAddAAMouseUpMS#1{\def\argi{#1}\ifx\argi\@empty + \def\eqAddAAMouseUpMS{}\else\def\eqAddAAMouseUpMS{#1}\fi} +\def\eqAddAAMouseUpMS{} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \subsection{An pushbutton to hold an icon appearance} +% I don't remember much about the \cs{eqIcon} command, don't remember +% how this is used. % \begin{macro}{\eqIcon} % Create a push button for displaying an icon. I've set this on read only, this % can be removed by saying \verb+\Ff{-\FfReadOnly}+/ @@ -9526,6 +10096,7 @@ if (!isQuizInitialized("@currQuiz")) { % \end{macrocode} % \end{macro} % \begin{macrocode} +\eq@restoreCats %</package> % \end{macrocode} % @@ -9580,6 +10151,21 @@ if (!isQuizInitialized("@currQuiz")) { % \end{macrocode} % \begin{macrocode} \newcommand{\dlLibSpecRespJS}{"none","undefined","empty"} +\newif\ifSubstVars\SubstVarsfalse % dps17 +\newif\ifShowAppr\ShowApprtrue % dps17 +\def\altApprOn{\ShowApprtrue} % dps17 +\def\altApprOff{\ShowApprfalse} % dps17 +\def\corrChoiceFullyOn{\def\eqCorrChoiceFully{true}} +\def\corrChoiceFullyOff{\def\eqCorrChoiceFully{false}} +\corrChoiceFullyOn +% \end{macrocode} +% Implement a local version of full corrections of MS and MS +% \changes{v8.1l}{2018/02/07}{Add local version of \string\cs{corrChoiceFullOn}} +% \begin{macrocode} +\def\corrLocalChoiceFullyOn{\def\eqCorrLocalChoiceFully{true}} % dpsf07 +\def\corrLocalChoiceFullyOff{\def\eqCorrLocalChoiceFully{false}} % dpsf07 +\def\resetLocalChoiceFully{\let\eqCorrLocalChoiceFully\@empty} % dpsf07 +\resetLocalChoiceFully % no local implementation \begin{insDLJS*}[exerquizLoaded]{exerquiz} % \end{macrocode} % \subsection{Global Data} @@ -9638,12 +10224,15 @@ var Score=0; var ptScore=0; var pcScore=0; var quizGrade="C"; +var NQuestions=0; +var NPointTotal=0; var e = Math.E; var pi = Math.PI; var replaceExclaim = \replaceexclaim; var negPointsAllowed = \negpointsallowed; var negPointsMarkupAllowed = \negpointsmarkupallowed; -var aQuizControl = new Array(); +%var aQuizControl = new Array(); +var aQuizControl = new Object; var RightWrong=new Array(); var ProbValue = new Array(); var ProbDist = new Array(); @@ -9961,10 +10550,18 @@ function addMathObject(UserInput) function ParseInput(UserInput) { var re, repi; +% \end{macrocode} +% When `a' is a variable, and the user types in `a cos(x)', exerquiz eventually removes spaces and this +% becomes `acos(x)', which is not is wanted. Early on, we replace `a' with `(a)' so it is interpreted as +% a factor: `a cos(x) becomes `(a) cos(x)', which when spaces are stripped out, becomes `(a)cos(x)'. +% \changes{v8.1b}{2017/09/06}{Enclosed literal `a' in parentheses to disambiguate `a cos' from `acos'.} +% \begin{macrocode} + re = /\b(a)\b/g; + UserInput = UserInput.replace(re, "(a)"); UserInput = stripWhiteSpace (UserInput); if (!ok2Continue) return null; % \end{macrocode} -% See if there are matching `\texttt{[]}', `\texttt{\{\}}' and `\texttt{()}'. +% See if there are matching `\texttt{[]}', `\verb~{}~' and `\texttt{()}'. % \begin{macrocode} for(var i=0; i< aGroup.length; i++) { @@ -9976,12 +10573,10 @@ function ParseInput(UserInput) } } % \end{macrocode} -% Replace `\texttt{[]}' and `\texttt{\{\}}' with `\texttt{()}'; only parentheses +% Replace `\texttt{[]}' and `\verb~{}~' with `\texttt{()}'; only parentheses % are used in JavaScript for grouping. % \begin{macrocode} UserInput = ChngAllGrpsToParens(UserInput); -% UserInput = UserInput.replace(/\[|\{/g, "\("); -% UserInput = UserInput.replace(/\]|\}/g, "\)"); % \end{macrocode} % If the \texttt{fact} function is defined, we attempt to replace user's input of the form % \texttt{<number>!} with \texttt{fact(<number>)}. @@ -10360,25 +10955,34 @@ function TypeParameters(v) % \end{macro} % \begin{macro}{ProcResp} % This function handles numerical answers or function of a single variable, x, -% that evaluate to a number. +% that evaluate to a number % \begin{macrocode} -function ProcResp(flag,CorrAns,n,epsilon,domain,indepVar,oComp) +function ProcResp(flag,CorrAns,n,epsilon,domain,indepVars,oComp) { if (!ProcessIt) return null; var fieldname = event.target.name; - var UserAns = event.value; + var bSubstVars=(arguments.length>7); // dps17 +% \end{macrocode} +% The introduction of multi-letter variables, necessitates a slight revision of the JavaScript function +% \texttt{ProcResp()}. This fundamental function, changes to this function must be propagated +% to \pkg{dljslib} to all `proc resp' function. +% \begin{macrocode} + var UserAns=(arguments.length>7)?arguments[7]:event.value; var success = _ProcResp(flag,CorrAns,UserAns,% -n,epsilon,domain,indepVar,oComp); +n,epsilon,domain,indepVars,oComp); % \end{macrocode} % 09/07/09 Added next line to avoid double alert boxes % \begin{macrocode} - if ( success == -1 || !ok2Continue ) return null; - if ( success == null ) { return syntaxError(), null; } + if ( success == -1 || !ok2Continue ) + { resetHeadsUp(flag,fieldname); return null; } // dps17 + if ( success == null ) + { resetHeadsUp(flag,fieldname); + return syntaxError(), null; } // dps17 return notifyField(success, flag, fieldname); } // changed name of var comp -> oComp -function _ProcResp(flag,CorrAns,UserAns,n,epsilon,domain,indepVar,oComp) -{ +function _ProcResp(flag,CorrAns,UserAns,n,epsilon,domain,% +indepVars,oComp){ ok2Continue = true; % \end{macrocode} % by preprocessing. @@ -10442,14 +11046,14 @@ function _ProcResp(flag,CorrAns,UserAns,n,epsilon,domain,indepVar,oComp) % \begin{macrocode} UserAns = ParseInput(UserAns); % \end{macrocode} -% Originally, the value of \texttt{indepVar} is a string of variables \texttt{"xyz"}. You can +% Originally, the value of \texttt{indepVars} is a string of variables \texttt{"xyz"}. You can % now have variables of the form \texttt{"r:x,i:n,r:y"}. Where the identifier \texttt{"r:"} indicates a -% real variable and \texttt{"i:"} indicates an integer variable. \texttt{indepVar} must be either +% real variable and \texttt{"i:"} indicates an integer variable. \texttt{indepVars} must be either % of the old style, or the new style, not a mixture of both, e.g. \texttt{"xyi:n"}. % \begin{macrocode} - indepVar = TypeParameters(indepVar); + indepVars = TypeParameters(indepVars); if (!ok2Continue) return null; - var success=randomPointCompare(n,domain,indepVar,% + var success=randomPointCompare(n,domain,indepVars,% epsilon,CorrAns,UserAns,comp); % \end{macrocode} % \paragraph*{postParse} (2011/10/05) The beginning of an idea, \texttt{postParse}. After it is determined @@ -10523,7 +11127,7 @@ function processSpecialParse(oParse,UserAns) { % true if the error of the random comparison is less than epsilon % false if the error of the random comparison is greater than epsilon % \begin{macrocode} -function randomPointCompare (n,domain,indepVar,epsilon,% +function randomPointCompare (n,domain,indepVars,epsilon,% CorrAns,userAns,comp) { var error, i, j, k; @@ -10544,7 +11148,7 @@ CorrAns,userAns,comp) -eval(endpoints[0]))*Math.random(); } var cXY = aXY.toString(); - error = comp(domain,cXY,indepVar,CorrAns,userAns); + error = comp(domain,cXY,indepVars,CorrAns,userAns); if (error == null) return null; if ( (error == -1) || (error > epsilon) ) {j=-1; break;} } @@ -10765,6 +11369,87 @@ function requireFormNot(UserAns, regexpr) { } } \end{newsegment} +\begin{newsegment}{Eq: Support for multi-letter variables} +if (!String.prototype.trim) { + String.prototype.trim = function () { + return this.replace(/^[\s\string\uFEFF\string\xA0]+|% +[\s\string\uFEFF\string\xA0]+$/g, ''); + }; +} +function _rplVarsBy(str1,str2) { + var re=new RegExp(str1,"g"); + var result=str1.replace(re,str2); + return result; +} +function processMathVars(str) { + var pos1,pos2,lead,tmp; + while ((pos1=str.indexOf("_rplVarsBy"))!=-1) { + pos2=str.indexOf("@"); + lead=str.substring(0,pos1); + tmp=str.substring(pos1,pos2); + str=str.substring(pos2+1); + tmp=eval(tmp); + str=lead+tmp+str; + } + str=str.replace(/\s/g,""); + return str; +} +getSubstValue.aSubsts=new Array(); // dps17 +function getSubstValue(v,s){ +/* + v=variable list, it may have the form "xyz", or if there + substitutions, it might look like "_rplVarsBy('theta','x')@"; + s=Either the user's answer or the author's answer. + + First develop an array of all variables are their substitutes. + ie, getSubstValue.aSubsts=[ "c","h", ["theta",x"], ["alpha",y],...]; +*/ + var pos1,pos2,tmp,args,re,arg1,arg2; +/* + change new style to old + New style: v="c,_rplVarsBy('theta->\u03B8','r:x')@,% +_rplVarsBy('alpha->\u03B1','r:y')@"; + Old style: v="c_rplVarsBy('theta->\u03B8','x')@% +_rplVarsBy('alpha->\u03B1','y')@"; +*/ + re=/([^'])(,)/g; + v=v.replace(re,'$1'); + re=/([ri]\string\:)+(\string\w)/g; + v=v.replace(re,'$2'); + getSubstValue.aSubsts=[]; // dps17 + var start=0; + while (true) { + v=v.substring(start); + pos1=v.indexOf("_rplVarsBy"); + if (pos1==-1) break; + pos2=v.indexOf("@"); + args=v.substring(pos1+10+1,pos2-1); + tmp=args.split(","); + arg1=eval(tmp[0].toString()); + tmp1=arg1.split("->"); + for (var i=0; i<tmp1.length; i++) + tmp1[i]=tmp1[i].trim(); + if (tmp1.length==1) getSubstValue.aSubsts.push(tmp1[0]); + else getSubstValue.aSubsts.push(tmp1); + arg2=eval(tmp[1].toString()); + re=new RegExp(tmp1[0],"g"); + s=s.replace(re,arg2); + start=pos2+1; + } + return s; +} +function RespBoxAppr(e){ + var value=(typeof e=="object")?e.value:e; + var re; + for (var i=0; i<getSubstValue.aSubsts.length; i++) { + if (typeof getSubstValue.aSubsts[i]=="object") { + re=new RegExp(getSubstValue.aSubsts[i][0],"g"); + value=(value.replace(re,getSubstValue.aSubsts[i][1],"g")); + } + } + return value; +} +\end{newsegment} % \end{macrocode} % \subsection{Text Fill-in} % Now the JS functions that process text fill-in questions. @@ -10893,7 +11578,7 @@ function InitMsg(msg) { return (\eqInitQuizMsg) } function syntaxError() { eqAppAlert(\eqSyntaxErrorUndefVar,3); } % \end{macrocode} % \begin{macrocode} -var lstOfQuizzes=new Array(); +var lstOfQuizzes=new Object(); % \end{macrocode} % There are four required parameters, if there is a fifth, that means % we have a grouped question, parameter 5 will be the group sub-problem number. @@ -11037,6 +11722,18 @@ function InitializeQuiz(qtfield,mark) { } return null; } +function resetHeadsUp(flag,fieldname) { + if (flag==1) return; + var pos1=fieldname.indexOf("."); + var pos2=fieldname.indexOf(".",pos1+1); + var baseName=fieldname.substring(pos1+1,pos2); + var oQName=eval(baseName); + var defaultColor=(typeof oQName.DefaultColorJSLoc=="undefined")% +?\defaultColorJS:oQName.DefaultColorJSLoc; + var f=this.getField(fieldname); + if (f!=null) f.strokeColor=defaultColor; + +} function neutralizeQuizzes() { for ( var qtfield in aQuizControl ) aQuizControl[qtfield] = 0; @@ -11107,11 +11804,11 @@ function GrpRight( a, nProb, qtfield ) var prod = 1; for ( var i=1; i <= l; i++) prod *= !!a[i]; return prod; - } function DisplayQuizResults(qtfield,nPointTotal,nQuestions) { Score = 0; ptScore = 0; + NPointTotal=nPointTotal; NQuestions=nQuestions; for (var i=1; i < RightWrong.length; i++) { if ( (typeof RightWrong[i] == "object" ) % @@ -11155,7 +11852,7 @@ function DisplayQuizResults(qtfield,nPointTotal,nQuestions) } } } -if ( !negPointsAllowed && (ptScore < 0) ) ptScore = 0; + if ( !negPointsAllowed && (ptScore < 0) ) ptScore = 0; if (ptScore == nPointTotal) pcScore = 100; else pcScore = util.printf("\%.1f", (100 * ptScore) / nPointTotal); var oQName=eval(qtfield); @@ -11287,10 +11984,52 @@ function correctQuiz(qtfield,nQuestions) var wrongAnsSymb=(typeof oQName.WrongAnsSymbJSLoc=="undefined")% ?\wrngAnsSymbJS:oQName.WrongAnsSymbJSLoc; % \end{macrocode} +% Implement a local version of fully correcting MC and MS questions. +% \changes{v8.1l}{2018/02/07}{Add local version of \string\cs{corrChoiceFullOn}} +% \begin{macrocode} + var bFullyCorrect=(typeof oQName.fullyCorrectLoc=="undefined")% +?\eqCorrChoiceFully:oQName.fullyCorrectLoc; // dpsf07 +% \end{macrocode} % MC or MS questions % \begin{macrocode} var f = this.getField("mcq." + qtfield); - if ( f != null) f.display = display.visible; +% if ( f != null) f.display = display.visible; +% \end{macrocode} +% \changes{v8.1f}{2017/12/04}{Added an option for MC question not to +% show the correct answer, but only the incorrect ones.} +% \begin{macrocode} + if ( f != null) { + if (bFullyCorrect) { // dpsf07 + f.display = display.visible; + } else { + for (var n=1; n<=nQuestions; n++) { + var h=this.getField("mc."+qtfield+"."+n); + var bOk=(h!=null); + if(bOk) var choiceType="mc"; + else { + h=this.getField("mck."+qtfield+"."+n); + bOk=(h!=null); + var choiceType="mck"; + } + if (bOk) { + var mcq=this.getField("mcq."+qtfield+"."+n); + var g=mcq.getArray(); + if (choiceType=="mc") { + for (var j=0; j< g.length; j++) { + g[j].display=(h.isBoxChecked(j))?% +display.visible:display.hidden; + } + } else { + var ck=h.getArray(); + for (var j=0; j< g.length; j++) { + g[j].display=(ck[j].isBoxChecked(0))?% +display.visible:display.hidden; + } + } + } + } + } + } f = this.getField("obj." + qtfield); if ( f != null ) { var a = f.getArray(); @@ -11537,30 +12276,30 @@ function chooseJSColor( b, c1, c2 ) { return ( b ) ? c1 : c2; } function notifyField(success, flag, fieldname) { - if ( flag != 0 ) - return (success)?true:false; + if ( flag != 0 ) + return (success)?true:false; % \end{macrocode} % if \texttt{flag == 0}, then we are working with a \texttt{shortquiz}, and immediate response % is needed. % \begin{macrocode} - var f = this.getField(fieldname); - var re=/^(obj|grpobj)\./; - var gname=fieldname.replace(re,"rbmarkup\."); - var g =this.getField(gname); - var isthereRBUP = ( g !=null ); + var f = this.getField(fieldname); + var re=/^(obj|grpobj)\./; + var gname=fieldname.replace(re,"rbmarkup\."); + var g =this.getField(gname); + var isthereRBUP = ( g !=null ); % \end{macrocode} % Extract the quiz name from the field name: \texttt{obj.QName.num} or \texttt{grpobj.QName.num} % \begin{macrocode} - var h = fieldname.replace(re,""); - var index=h.indexOf("."); - var oQName = eval(h.substring(0,index)); - var rightColor=(typeof oQName.RightColorJSLoc=="undefined")% + var h = fieldname.replace(re,""); + var index=h.indexOf("."); + var oQName = eval(h.substring(0,index)); + var rightColor=(typeof oQName.RightColorJSLoc=="undefined")% ?\rghtColorJS:oQName.RightColorJSLoc; - var rightSymb=(typeof oQName.RightColorJSLoc=="undefined")% + var rightSymb=(typeof oQName.RightColorJSLoc=="undefined")% ?\rghtAnsSymbJS:oQName.RightAnsSymbJSLoc; - var wrongColor=(typeof oQName.WrongColorJSLoc=="undefined")% + var wrongColor=(typeof oQName.WrongColorJSLoc=="undefined")% ?\wrngColorJS:oQName.WrongColorJSLoc; - var wrongSymb=(typeof oQName.WrongAnsSymbJSLoc=="undefined")% + var wrongSymb=(typeof oQName.WrongAnsSymbJSLoc=="undefined")% ?\wrngAnsSymbJS:oQName.WrongAnsSymbJSLoc; if (success) { f.strokeColor = rightColor; @@ -11652,37 +12391,37 @@ app.clearTimeOut(oNoPeekTimer);",5); var oCB=\bcheckboxused function OnBlurRespBox (retn) { - var qname = arguments[1]; - var oQName = eval(qname); - var respMsg; - var cTitle = "AcroTeX eDucation Bundle"; - if (retn != null) { - if ( typeof appAlerts[qname] == "undefined") - appAlerts[qname] = {bAfterValue: false, % + var qname = arguments[1]; + var oQName = eval(qname); + var respMsg; + var cTitle = "AcroTeX eDucation Bundle"; + if (retn != null) { + if ( typeof appAlerts[qname] == "undefined") + appAlerts[qname] = {bAfterValue: false, % cMsg: "\doNotShowAgainMsg"}; - var respMsg = (retn) ? \eqsqrtmsg\space : \eqsqwgmsg; - if ( (event.target == this) || !oCB) - eqAppAlert({ cMsg: respMsg, nIcon: 3, cTitle: cTitle }); - else { - if ( ! appAlerts[arguments[1]].bAfterValue ) - eqAppAlert({ cMsg: respMsg, nIcon: 3, cTitle: cTitle, % + var respMsg = (retn) ? \eqsqrtmsg\space : \eqsqwgmsg; + if ( (event.target == this) || !oCB) + eqAppAlert({ cMsg: respMsg, nIcon: 3, cTitle: cTitle }); + else { + if ( ! appAlerts[arguments[1]].bAfterValue ) + eqAppAlert({ cMsg: respMsg, nIcon: 3, cTitle: cTitle, % oCheckbox: appAlerts[qname]}); - } } - else { - var re=/^(obj|grpobj)\./; - var gname=event.target.name.replace(re,"rbmarkup\."); - var g =this.getField(gname); - var isthereRBUP = ( g !=null ); - var str = event.target.value.toString(); - if (str.replace(/\s/g,"") == "") { - var defaultColor=% + } + else { + var re=/^(obj|grpobj)\./; + var gname=event.target.name.replace(re,"rbmarkup\."); + var g =this.getField(gname); + var isthereRBUP = ( g !=null ); + var str = event.target.value.toString(); + if (str.replace(/\s/g,"") == "") { + var defaultColor=% (typeof oQName.DefaultColorJSLoc=="undefined")% ?color.black:oQName.DefaultColorJSLoc; - if (isthereRBUP) g.display=display.hidden; - event.target.strokeColor = defaultColor; - } + if (isthereRBUP) g.display=display.hidden; + event.target.strokeColor = defaultColor; } + } } function jmpToNamedDest(fName,cDest,bAlert) { if ( (typeof appAlerts[fName]!="undefined" % |