summaryrefslogtreecommitdiff
path: root/texmf-dist/source
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2018-06-16 14:40:57 +0900
committerNorbert Preining <norbert@preining.info>2018-06-16 14:40:57 +0900
commit5bf15133ae1a0745a8a5093950961c4e23dd8f5b (patch)
tree93f781068c7a66e17760e8ce4a3ad4a87b72f884 /texmf-dist/source
parent17a613f5d465d7e6560f3e4a76e1c7298889cbdb (diff)
add eq-save
Diffstat (limited to 'texmf-dist/source')
-rw-r--r--texmf-dist/source/latex/eq-save/eq-save.dtx646
-rw-r--r--texmf-dist/source/latex/eq-save/eq-save.ins60
2 files changed, 706 insertions, 0 deletions
diff --git a/texmf-dist/source/latex/eq-save/eq-save.dtx b/texmf-dist/source/latex/eq-save/eq-save.dtx
new file mode 100644
index 00000000..180d42fe
--- /dev/null
+++ b/texmf-dist/source/latex/eq-save/eq-save.dtx
@@ -0,0 +1,646 @@
+% \iffalse
+%<*copyright>
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% eq-save package, %%
+%% Copyright (C) 2017-2018 %%
+%% dpstory@uakron.edu %%
+%% %%
+%% This program can redistributed and/or modified under %%
+%% the terms of the LaTeX Project Public License %%
+%% Distributed from CTAN archives in directory %%
+%% macros/latex/base/lppl.txt; either version 1.2 of %%
+%% the License, or (at your option) any later version. %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%</copyright>
+%<package>\NeedsTeXFormat{LaTeX2e}[1997/12/01]
+%<package>\ProvidesPackage{eq-save}
+%<package> [2018/04/07 v1.1 eq-save: save exerquiz quizzes and resume (dps)]
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage[colorlinks,hyperindex=false]{hyperref}
+\usepackage{calc}
+\let\uif\textsf\let\app\textsf
+\let\pkg\textsf\let\env\texttt
+\let\opt\texttt
+\def\ameta#1{$\langle\textit{\texttt{#1}}\rangle$}
+\def\psf#1{\textsf{\textbf{#1}}}
+%\pdfstringdefDisableCommands{\let\\\textbackslash}
+\OnlyDescription % comment out for implementation details
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\InputIfFileExists{aebdocfmt.def}{\PackageInfo{eq-save}{Inputting aebdocfmt.def}}
+ {\def\IndexOpt{\DescribeMacro}\def\IndexKey{\DescribeMacro}\let\setupFullwidth\relax
+ \PackageInfo{eq-save}{aebdocfmt.def cannot be found}}
+\begin{document}
+\def\CMD#1{\textbackslash#1}
+ \GetFileInfo{eq-save.sty}
+ \title{\textsf{eq-save}: Saving \pkg{exerquiz} quizzes and resuming}
+ \author{D. P. Story\\
+ Email: \texttt{dpstory@acrotex.net}}
+ \date{processed \today}
+ \maketitle
+ \tableofcontents
+ \let\Email\texttt
+ \renewenvironment{theglossary}{%
+ \let\efill\relax
+ \begin{itemize}}{\end{itemize}}
+ \value{GlossaryColumns}=1
+ \DocInput{eq-save.dtx}
+\IfFileExists{\jobname.ind}{\newpage\setupFullwidth\par\PrintIndex}{\paragraph*{Index} The index goes here.\\Execute
+ \texttt{makeindex -s gind.ist -o eq-save.ind eq-save.idx} on the command line and recompile
+ \texttt{eq-save.dtx}.}
+\IfFileExists{\jobname.gls}{\PrintChanges}{\paragraph*{Change History} The list of changes goes here.\\Execute
+ \texttt{makeindex -s gglo.ist -o eq-save.gls eq-save.glo} on the command line and recompile
+ \texttt{eq-save.dtx}.}
+\end{document}
+%</driver>
+% \fi
+% \MakeShortVerb{|}
+% \InputIfFileExists{aebdonotindex.def}{\PackageInfo{web}{Inputting aebdonotindex.def}}
+% {\PackageInfo{web}{cannot find aebdonotindex.def}}
+% \begin{macrocode}
+% Begin Package
+%<*package>
+% \end{macrocode}
+% The option \IndexOpt{devmode}\opt{devmode} does not require the user to enter his or her name
+% in the name field, if the \cs{nameField} and \cs{BeginNoPeeking} commands are present; otherwise it has no effect.
+% The \IndexOpt{!devmode}\opt{!devmode} is the logical negation of \opt{devmode}, its the same as no option
+% passed.
+% \begin{macrocode}
+\DeclareOption{devmode}{\def\devMode{true}}
+\DeclareOption{!devmode}{\def\devMode{false}}
+\def\devMode{false}
+\ProcessOptions
+\RequirePackage{exerquiz}[2017/07/30]
+\RequirePackage{atbegshi}
+\edef\ap@restoreCats{%
+ \catcode`\noexpand\"=\the\catcode`\"\relax
+ \catcode`\noexpand\,=\the\catcode`\,\relax
+ \catcode`\noexpand\(=\the\catcode`\(\relax
+ \catcode`\noexpand\!=\the\catcode`\!\relax
+}
+\@makeother\"\@makeother\,\@makeother\(\@makeother\!
+% \end{macrocode}
+% \changes{v1.0}{2017/08/12}{Wrote initial documentation, set version as v1.0}
+% \section{Introduction}
+% Work, on what ultimately became this package, was initiated by a user Manfred~S. He and his team were writing
+% practice documents for their students that included \env{oQuestion}, \env{shortquiz}, and \env{quiz} environments from the
+% \pkg{exerquiz} package. It was desired for the student to enter his/her name first, then begin the practice document.
+% After a while, the student may become tired or disinterested, so he/she save the document.
+% He wanted to take advantage of the ability of Adobe Acrobat Reader 11 or greater (DC and beyond) to save the form data,
+% something it couldn't do prior. Later the student becomes motivated and returns to the document to continue working through
+% the questions.
+%
+% Sounds good, but wait! \env{oQuestion}, \env{shortquiz}, and \env{quiz} environments were not designed
+% for this. There are a lot of JavaScript variables, arrays, objects containing information about the quizzes as they are
+% attempted. This data is normally disposed of when the reader takes another quiz. Certainly, as the user saves and closes
+% the document all variables, arrays, objects are lost. This package attempts to save all essential information when
+% the user saves the document, the information is saved in a hidden text field. Upon opening the document again,
+% the essential data is restored.
+%
+% A professor might want this feature for a tutorial. The tutorial (rather long) can have questions from
+% \env{oQuestion}, \env{shortquiz}, and \env{quiz} environments. The student can save, and return to the
+% reading of the tutorial and the answering of the questions. A self-paced tutorial does not need a name field
+% to act as a `gatekeeper' to the document, as is the need of Manfred~S.
+%
+%
+% \section{Commands of this package}
+% The \DescribeMacro{\nameField}\cs{nameField} command insert a text field into which the student enters
+% his name; otherwise, he cannot continue to the next page. Changing your name after you've begun to work
+% on the questions clears the answer to all quizzes; this is an annoyance factor, a feeble attempt to reduce
+% cheating. When \cs{nameField} is used, the top of the next page should be \cs{BeginNoPeeking}.
+% \begin{macrocode}
+\newcommand\nameField[4][]{\textField[#1
+ \AAkeystroke{chk4PassToQuestions(event);}
+ \AAformat{if(typeof oRecordOfQuizData=="undefined") \r\t
+ var oRecordOfQuizData=new Object();\r
+ try{IhrNameFormat(event);}catch(e){}
+ }]{#2}{#3}{#4}}
+% \end{macrocode}
+% \DescribeMacro{\hiddenScoreData}\cs{hiddenScoreData} text field.
+% It has zero dimensions, takes up no (horizontal) {\TeX} space, and is hidden. It is placed under the name field.
+% This field, when the document is saved, receive all essential quiz data. It is read again when the document
+% is opened to restore the quiz data. We give this field an initial value, for otherwise, the PDF viewer will
+% not scan this field on opening.
+% \begin{macrocode}
+\newcommand{\hiddenScoreData}{\makebox[0pt][l]{%
+\textField[\F\FHidden\V{({})}\DV{({})}\AAformat{%
+ if(typeof oRecordOfQuizData=="undefined")\r\t
+ oRecordOfQuizData={};}\BG{}\BC{}]{holdScoreData}{0bp}{0bp}}}
+\AtBeginShipoutFirst{\hiddenScoreData}
+% \end{macrocode}
+% We place this field on the first page, upper left corner. It will be scanned by the PDF viewer (Reader)
+% and it will define the object \texttt{oRecordOfQuizData} that will hold essential quiz data.
+%
+% \paragraph*{Displaying and clearing results} As the user/student progresses through the documents, he
+% can see his success rate by viewing the text fields below.
+%
+% The \DescribeMacro{\sooField}\cs{sooField} (soo=score out of) displays the combined score: `12 out of 16', for example.
+% The phase may be redefined for language purposes by redeclaring the command \cs{declareScorePhrase}, the English
+% declaration is \verb~\declareScorePhrase{#1+"\space\eqOutOf\space"+#2}~, see the documentation above for this command.
+%
+% The \DescribeMacro{\sField}\cs{sField} is one that holds only the score, while
+% \DescribeMacro{\ooField}\cs{ooField} holds the `out of' value.
+% \begin{macrocode}
+\newcommand{\sField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
+ {\eqsroot.Score}{#2}{#3}}
+\newcommand{\ooField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
+ {\eqsroot.OutOf}{#2}{#3}}
+\newcommand{\sooField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
+ {\eqsroot.ScoreComb}{#2}{#3}}
+% \end{macrocode}
+% Now we do the same thing for the points score. \DescribeMacro{\psField}\cs{psField} holds the total
+% number of points awarded; \DescribeMacro{\pooField}\cs{pooField} is the total number of points;
+% \DescribeMacro{\psooField}\cs{psooField}
+% \begin{macrocode}
+\newcommand{\psField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
+ {\eqsroot.ptScore}{#2}{#3}}
+\newcommand{\pooField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
+ {\eqsroot.ptOutOf}{#2}{#3}}
+\newcommand{\psooField}[3][]{\textField[\Ff{\FfReadOnly}#1]%
+ {\eqsroot.ptScoreComb}{#2}{#3}}
+% \end{macrocode}
+% We supply a global clearing button. This button clear all results in the document, questions posed
+% by \env{oQuestions}, \env{shortquiz}, and \env{quiz} environments.
+% \begin{macrocode}
+\newcommand{\clearAllField}[3][]{\pushButton[\CA{Clear All}#1
+ \AAmouseup{clearAllSQElements();}]{globalClearAll}{#2}{#3}}
+% \end{macrocode}
+%
+% \paragraph*{Set action keys} We modify certain action keys to save the information we'll need later when the document is saved.
+% The \cs{setActionKeys} is a new feature of \pkg{exerquiz} (2017/07/29) and is used to add JavaScript
+% actions to certain key elements of the quiz environments. This is how we are able to preserve and later
+% restore the quiz data. The command \DescribeMacro{\eqsSetActionKeys}\cs{eqsSetActionKeys} is expanded
+% when \cs{DeclareReportRootName} is expanded. If the author declares a new root, the \cs{setActionKeys},
+% which depend on \cs{eqsroot}, must be re-emitted.
+% \begin{macrocode}
+\newcommand{\eqsSetActionKeys}{%
+ \setActionKeys{%
+% \end{macrocode}
+% (2018/04/07) Removing \cs{AddAAFormat}, there is no test for null later in the code.
+% \changes{v1.1}{2018/04/07}{No need for the change to \string\cs{AddAAFormat}}
+% \begin{macrocode}
+% \AddAAFormat{\if\eqQuizType\isSQZ
+% if (typeof event.target.isCorrect=="undefined")\r\t
+% event.target.isCorrect=null;\fi}
+ \AddAAKeystroke{\if\eqQuizType\isSQZ
+ event.target.isCorrect=(retn)?1:0;\r\t
+ oRecordOfQuizData[event.target.name]=event.target.isCorrect;\r\t
+ cntCorrectResponses();\fi}
+ \AddAAMouseUpMC{\if\eqQuizType\isSQZ
+ event.target.isCorrect=\Ans@choice;\r
+ oRecordOfQuizData[event.target.name]=event.target.isCorrect;\r
+ cntCorrectResponses();\fi}
+ \AddAAMouseUpMS{\if\eqQuizType\isSQZ
+ event.target.isCorrect=\Ans@choice;\r
+ oRecordOfQuizData[event.target.name]=event.target.isCorrect;\r
+ cntCorrectResponses();\fi}
+ }%
+}
+% \end{macrocode}
+% \paragraph*{Modify actions of Begin Quiz and End Quiz} These actions may be modified using the
+% two commands \cs{postInitQuiz} and \cs{postSubmitQuiz}. They are used to insert the \texttt{cntCorrectResponses()} call
+% into the action performed by the `Begin Quiz' and `End Quiz' buttons. \emph{It is assumed the document
+% author is not otherwise using these two commands.}
+% \begin{macrocode}
+\def\postInitQuiz{%
+ var f=this.getField("ScoreData.\oField");\r
+ f.value="0;0;0;0";\r
+ cntCorrectResponses();}
+\def\postSubmitQuiz{%
+ oRecordOfQuizData["ScoreData.\oField"]=%
+ [1*Score,1*NQuestions,1*ptScore,1*NPointTotal];\r\t\t
+ cntCorrectResponses();\r
+}
+% \end{macrocode}
+% \paragraph*{Open Page Action} We add a page open event to restore the data as needed. We only do this once
+% per document session.
+% \begin{macrocode}
+\thisPageAction{\JS{if(!restoreQuizData.hasRestoredData)\r\t
+ var rqdTO=(app.setTimeOut("restoreQuizData();app.clearTimeOut(rqdTO);%
+ restoreQuizData.hasRestoredData=true",1000));}}{}
+% \end{macrocode}
+% \paragraph*{Action prior to saving} It is important to save the quiz data, we can only do that if we save
+% it to a field, the value of the field will be saved. We save the data to a hidden text field
+% \texttt{"holdScoreData"}, this field is required.
+% \begin{macrocode}
+\begin{willSave}
+isAQuizUnfinishedAtSave();
+if (typeof oRecordOfQuizData !="undefined") collectQuizData();
+\end{willSave}
+% \end{macrocode}
+% \paragraph*{No peeking} If the \cs{nameField} command is used,
+% use \DescribeMacro{\BeginNoPeeking}\cs{BeginNoPeeking} command can optionally appear on the
+% first page that contain content the author does not want the user to peek at. The
+% JavaScript string \DescribeMacro{\EnterNameFirstMsg}\cs{EnterNameFirstMsg} appears in the alert
+% box if the user goes to a forbidden page without first enther his name into the \cs{nameField}.
+% May be redefined for local languages.
+% \begin{macrocode}
+\flJSStr[noquotes,noparens]{\EnterNameFirstMsg}{You must enter
+ your name first!}
+\def\declareScorePhrase#1{\def\dclScorePhse(##1)(##2){#1}}
+\declareScorePhrase{#1+"\space\eqOutOf\space"+#2}
+\def\BeginNoPeeking{\def\IhrNamePO{\thisPageAction{%
+ \JS{if(!_docDevMode&&!_passToQuestions){\r\t
+ this.pageNum=0;\r\t
+ NoNameMsg=app.setTimeOut("app.alert('\EnterNameFirstMsg');%
+ app.clearTimeOut(NoNameMsg);",25);}}}{}}%
+% Page option for this page
+ \IhrNamePO
+% page open for all other pages
+ \AtBeginShipout{\IhrNamePO}%
+}
+% \end{macrocode}
+% The command \DescribeMacro{\DeclareReportRootName}\cs{DeclareReportRootName} may never need to be used, but just
+% in case, it can only be used once in the preamble. It names the parent (or root) name of the text fields that
+% will contain the running summary of the user's efforts in the document. The default root name is \texttt{SUMRY}.
+% \begin{macrocode}
+\newcommand{\DeclareReportRootName}[1]{\def\eqsroot{#1}%
+ \eqsSetActionKeys}
+\DeclareReportRootName{SUMRY}
+\@onlypreamble{\DeclareReportRootName}
+% \end{macrocode}
+% One of the problems is the quizzes and shortquizzes are not known when the document is first
+% opened. Normally this is not a problem, but in this application we need to know them. This problem
+% is solved by two events: at the end of the document the list of quizzes is known, it is save to
+% the auxiliary file \texttt{qzlist-\string\jobname.cut}, then this file is input back into the preamble, parsed,
+% and entered into the document level JavaScript through the command \cs{jsCodeForQzs}. The contents
+% of the aux file may look like: \texttt{\string\jsForQzs\space qz1;qz2;oQ1;sQ1;\string\@nil}. The internal command
+% \DescribeMacro{\jsCodeForQzs}\cs{jsCodeForQzs} parses this line at the semicolons; as a result, \cs{jsCodeForQzs}
+% expands to
+%\begin{verbatim}
+%var qz1=new Object();
+%var qz2=new Object();
+%var oQ1=new Object();
+%var sQ1=new Object();
+%\end{verbatim}
+% \begin{macrocode}
+\let\jsCodeForQzs\@empty\def\semiColon{;}\let\itsNonEmpty=0
+\def\jsForQzs#1\@nil{\jsForQzsi#1;;\@nil}
+\def\jsForQzsi#1;#2\@nil{\def\argii{#2}\ifx\argii\semiColon
+ \let\eqs@next\relax\else
+ \let\itsNonEmpty=1%
+ \g@addto@macro\jsCodeForQzs{var #1=new Object();^^J}%
+ \def\eqs@next{\jsForQzsi#2\@nil}\fi\eqs@next}
+% \end{macrocode}
+% We input the file that is created at the end of the document. We do a \cs{AtEndOfPackage} because
+% the command \cs{jsCodeForQzs} must be well defined by the time the document JavaScript are inserted.
+% \begin{macrocode}
+\AtEndOfPackage{\InputIfFileExists{qzlist-\jobname.cut}{}{}}
+% \end{macrocode}
+% At the end of the document after all quizzes and shortquizzes are known, we save them to
+% the file \texttt{qzlist-\string\jobname.cut}, they are then input in the preamble.
+% The \DescribeMacro{\saveListofQzs}\cs{saveListofQzs} writes the name of each quiz to an
+% semi-colon delimited list.
+% \begin{macrocode}
+\let\jsForQzsHold\@empty
+\let\cListOfQuizNames\@empty
+\let\cListOfSQuizNames\@empty
+\let\eqsHandleOpen=0
+\def\saveListofQzs{%
+ \ifx\ListOfQuizNames\@empty\else
+ \let\jsForQzsHold\@empty
+ \let\cListOfQuizNames\@empty
+ \edef\ListOfQuizNames{\expandafter\@gobble\ListOfQuizNames}
+ \immediate\openout\CommentStream=qzlist-\jobname.cut
+ \let\eqsHandleOpen=1
+ \expandafter\@for\expandafter
+ \@qz\expandafter:\expandafter=\ListOfQuizNames\do{%
+ \edef\@tmpExp{\noexpand
+ \g@addto@macro\noexpand\jsForQzsHold{\@qz;}}\@tmpExp
+ \edef\@tmpExp{\noexpand
+ \g@addto@macro\noexpand\cListOfQuizNames{,"\@qz"}}\@tmpExp
+ }%
+ \fi
+ \ifx\ListOfSQuizNames\@empty\else
+ \if\eqsHandleOpen0
+ \let\jsForQzsHold\@empty
+ \immediate\openout\CommentStream=qzlist-\jobname.cut
+ \let\eqsHandleOpen=1\fi
+ \let\cListOfSQuizNames\@empty
+ \edef\ListOfSQuizNames{\expandafter\@gobble\ListOfSQuizNames}
+ \expandafter\@for\expandafter\@qz
+ \expandafter:\expandafter=\ListOfSQuizNames\do{%
+ \edef\@tmpExp{\noexpand\g@addto@macro\noexpand
+ \jsForQzsHold{\@qz;}}\@tmpExp
+ \edef\@tmpExp{\noexpand
+ \g@addto@macro\noexpand\cListOfSQuizNames{,"\@qz"}}\@tmpExp
+ }%
+ \immediate\write\CommentStream{%
+ \string\jsForQzs\space\jsForQzsHold\string\@nil}
+ \fi
+ \if\eqsHandleOpen1
+ \ifx\ListOfQuizNames\@empty\else
+ \immediate\write\CommentStream{%
+ \string\def\string\cListOfQuizNames{\expandafter
+ \@gobble\cListOfQuizNames}}
+ \fi
+ \ifx\ListOfSQuizNames\@empty\else
+ \immediate\write\CommentStream{%
+ \string\def\string\cListOfSQuizNames{\expandafter
+ \@gobble\cListOfSQuizNames}}
+ \fi
+ \fi
+}
+% \end{macrocode}
+% Expand \cs{saveListofQzs} at the end of the document.
+% \begin{macrocode}
+\AtEndDocument{\saveListofQzs}
+% \end{macrocode}
+% \section{Document JavaScript}
+% \begin{macrocode}
+\dlJSStr{\eqerrUnfinishQuizAtSave}
+ {One of your quizzes is not finished, you will lose those responses.}
+\begin{insDLJS}{gcnt}{eq-save: Save and Resume JS support}
+var _passToQuestions=false;
+var oRecordOfQuizData;
+var _docDevMode=\devMode;
+var aQzList=new Array(\cListOfQuizNames);
+var aSqList=new Array(\cListOfSQuizNames);
+\jsCodeForQzs%
+cntCorrectResponses.nCorrectInDoc=0;
+cntCorrectResponses.nOutOfInDoc=0;
+cntCorrectResponses.nPtsCorrectInDoc=0;
+cntCorrectResponses.nPtsOutOfInDoc=0;
+% \end{macrocode}
+%\leavevmode\IndexJS{cntCorrectResponses()}is the workhorse of \pkg{eq-save}. It keeps tabs on the
+%total number of correct answers and the total number of questions. All \env{shortquiz}es are known immediately,
+%but results from \env{quiz} environments are not known until the student presses the `End Quiz' button.
+% \begin{macrocode}
+function cntCorrectResponses() {
+ var f=this.getField("\eqsroot");
+ if (f==null) return;
+ var g=f.getArray();
+% \end{macrocode}
+% \textbf{Naming convention:}\\\null\qquad\texttt{\string\eqsroot.ScoreComb},
+% \texttt{\string\eqsroot.Score}, \texttt{\string\eqsroot.OutOf}\\[3pt]
+% It is expected that the length \texttt{g.length=1\string|2\string|3}\\\null\quad
+% if \texttt{g.length=1}, we expect the field to be \texttt{\string\eqsroot.ScoreComb},\\\null\quad
+% if \texttt{g.length=2}, we expect \texttt{\string\eqsroot.Score}
+% and \texttt{\string\eqsroot.OutOf}, and\\\null\quad
+% if \texttt{g.length=3}, report all three
+% \begin{macrocode}
+ var fld1="\eqsroot.Score";
+ var fld2="\eqsroot.OutOf";
+ var fld3="\eqsroot.ScoreComb";
+ var fld4="\eqsroot.ptScore";
+ var fld5="\eqsroot.ptOutOf";
+ var fld6="\eqsroot.ptScoreComb";
+ cntCorrectResponses.nCorrectInDoc=0;
+ cntCorrectResponses.nOutOfInDoc=0;
+ cntCorrectResponses.nPtsCorrectInDoc=0;
+ cntCorrectResponses.nPtsOutOfInDoc=0;
+ var pos,baseName;
+ for (var i=0; i<this.numFields; i++) {
+ fname=this.getNthFieldName(i);
+ baseName=fname+"..";
+ pos=baseName.indexOf(".");
+ baseName=baseName.substring(pos+1);
+ pos=baseName.indexOf(".");
+ baseName=baseName.substring(0,pos);
+ if (aQzList.indexOf(baseName)!=-1) {
+ continue;
+ }
+ pos=fname.indexOf(".");
+ var root=fname.substring(0,pos);
+ if (root=="obj"|root=="grpobj") {
+ var f=this.getField(fname);
+% \end{macrocode}
+% Removing test for isCorrect, it can lead to some field not being
+% included when they should.
+% \changes{v1.1}{2018/04/07}{Removed test for isCorrect}
+% \begin{macrocode}
+% if (typeof f.isCorrect=="undefined") continue;
+ cntCorrectResponses.nOutOfInDoc+=1;
+ if (f.isCorrect==1) {
+ cntCorrectResponses.nCorrectInDoc+=1;
+ }
+ } else if (root=="mcq"||root=="mck"){
+ continue;
+ } else if (fname.substring(0,2)=="mc") {
+% \end{macrocode}
+% For MC within a quiz, there are two fields, name as indicated above.
+% if the second field exists, we ignore this field and continue.
+% \begin{macrocode}
+ var tst4qz="mcq"+fname.substring(2);
+ var otst4qz=this.getField(tst4qz);
+ if (otst4qz!=null)continue;
+% \end{macrocode}
+% Distinguish between multiple choice and multiple selection
+% \begin{macrocode}
+ var f=this.getField(fname);
+ var aResults=fname.match(/\./g);
+ if (aResults.length>2) {
+ // multiple selection
+ if (f.exportValues[0][0]==1) {
+ cntCorrectResponses.nOutOfInDoc+=1;
+ if (f.isBoxChecked(0)) {
+ cntCorrectResponses.nCorrectInDoc+=1;
+ }
+ }
+ } else {
+ // multiple choice
+ cntCorrectResponses.nOutOfInDoc+=1;
+ if (f.value[0]==1) {
+ cntCorrectResponses.nCorrectInDoc+=1;
+ }
+ }
+ }
+ }
+ addInQuizResults();
+% \end{macrocode}
+% We now display the totals results.
+% \begin{macrocode}
+ f=this.getField(fld1);
+ if(f!=null)f.value=cntCorrectResponses.nCorrectInDoc;
+ f=this.getField(fld2);
+ if(f!=null)f.value=cntCorrectResponses.nOutOfInDoc
+ var f=this.getField(fld3);
+ if (f!=null)f.value=(\dclScorePhse(cntCorrectResponses.nCorrectInDoc)%
+(cntCorrectResponses.nOutOfInDoc));
+ f=this.getField(fld4);
+ if(f!=null)f.value=cntCorrectResponses.nPtsCorrectInDoc;
+ f=this.getField(fld5);
+ if(f!=null)f.value=cntCorrectResponses.nPtsOutOfInDoc
+ var f=this.getField(fld6);
+ if (f!=null)
+ f.value=(\dclScorePhse(cntCorrectResponses.nPtsCorrectInDoc)%
+(cntCorrectResponses.nPtsOutOfInDoc));
+}
+% \end{macrocode}
+% \leavevmode\IndexJS{addInQuizResults()} is called by \texttt{cntCorrectResponses()} to add in the results
+% from the quizzes, if known. Because `Begin Quiz' and `End Quiz' can be links (not recommended) we save
+% the results of the quiz as the value of the field \texttt{ScoreData.\ameta{quizName}}. \pkg{exerquiz}
+% package save the quiz data in the form \texttt{"Score;\penalty0NQuestions;\penalty0ptScore;\penalty0NPointTotal"}.
+% This string can be split and the individual
+% values may be retrieved.
+% \begin{macrocode}
+function addInQuizResults() {
+ var results,value,score,outof;
+% \end{macrocode}
+% Coming into this function, the calculations so far are for \env{oQuestion} and \env{shortquiz} environments, these normally
+% don't have points assigned, and we do not support them if they do. Instead, we'll assign them to the points
+% \begin{macrocode}
+ cntCorrectResponses.nPtsCorrectInDoc=%
+cntCorrectResponses.nCorrectInDoc;
+ cntCorrectResponses.nPtsOutOfInDoc=cntCorrectResponses.nOutOfInDoc;
+ for (var i=0; i<aQzList.length; i++) {
+ var f=this.getField("ScoreData."+aQzList[i]);
+ if (f!=null) {
+ if (f.value!="") {
+ aTmp=f.value.split(";");
+ cntCorrectResponses.nCorrectInDoc+=(1*aTmp[0]);
+ cntCorrectResponses.nOutOfInDoc+=(1*aTmp[1]);
+ cntCorrectResponses.nPtsCorrectInDoc+=(1*aTmp[2]);
+ cntCorrectResponses.nPtsOutOfInDoc+=(1*aTmp[3]);
+ }
+ }
+ }
+}
+% \end{macrocode}
+% \leavevmode\IndexJS{clearAllSQElements()} clears all the quiz fields (all types). Much of the code
+% here is copied from \pkg{exerquiz}.
+% \begin{macrocode}
+function clearAllSQElements() {
+ var fname;
+ // clear any short quizzes and any supportive elements
+ for (var i=0; i<aSqList.length; i++) {
+ ProcessIt = false;
+ if ( typeof eval(aSqList[i])== "undefined" )
+ eval(aSqList[i])= new Object();
+ if (typeof appAlerts[aSqList[i]] == "undefined")
+ appAlerts[aSqList[i]] = new Object();
+ this.resetForm(new Array("mc."+aSqList[i],"obj."+aSqList[i],%
+"tally."+aSqList[i],"grpobj."+aSqList[i]));
+ var f = this.getField("obj."+aSqList[i]);
+ if ( f != null ) f.strokeColor=\ifx\defaultColorJSLoc\@empty%
+\defaultColorJS\else\defaultColorJSLoc\fi;
+ f = this.getField("grpobj."+aSqList[i]);
+ if ( f != null ) f.strokeColor=\ifx\defaultColorJSLoc\@empty%
+\defaultColorJS\else\defaultColorJSLoc\fi;
+ f = this.getField("rbmarkup."+aSqList[i]);
+ if ( f != null ) f.display=display.hidden;
+ eval(aSqList[i]).Grp = {};
+ appAlerts[aSqList[i]].bAfterValue=false;
+ ProcessIt=true;
+ }
+ isAQuizUnfinished.check=true;
+ // clear any quizzes and any supportive elements
+ for (var i=0; i<aQzList.length; i++) {
+ InitializeQuiz(aQzList[i],1);
+ aQuizControl[aQzList[i]] = 0;
+ }
+% \end{macrocode}
+% Here's where we clear all the field with parent names of
+% \cs{eqsroot} (\texttt{SUMRY}), \texttt{holdScoreData}, and \texttt{ScoreData}.
+% \begin{macrocode}
+ this.resetForm(["\eqsroot","holdScoreData","ScoreData"]);
+ oRecordOfQuizData=new Object();
+}
+% \end{macrocode}
+% \leavevmode\IndexJS{chk4PassToQuestions()} This function is used in the keystroke and format
+% phase of the \cs{nameField} command. If the student/user clears the field or changes the value
+% of the field once it has been committed, \texttt{chk4PassToQuestions()} then calls \texttt{clearAllSQElements()}
+% to clear all fields.
+% \begin{macrocode}
+chk4PassToQuestions.entered=false;
+function chk4PassToQuestions(event) {
+ if(event.willCommit) {
+ if (chk4PassToQuestions.entered) {
+ _passToQuestions=false;
+ clearAllSQElements();
+ this.dirty=false;
+ return;
+ }
+ if(event.value!="") {
+ var value=""+event.value;
+ value = value.replace(/\s/g,"");
+ if(value==null || value.length==0) {
+ _passToQuestions=false;
+ chk4PassToQuestions.entered=false;
+ } else {
+ _passToQuestions=true;
+ chk4PassToQuestions.entered=true;
+ clearAllSQElements();
+ this.dirty=false;
+ }
+ }
+ }
+}
+% \end{macrocode}
+% \leavevmode\IndexJS{collectQuizData()} is called by the \texttt{willSave} event. It save
+% the object \texttt{oRecordOfQuizData} to the field \texttt{holdScoreData} as a string.
+% \begin{macrocode}
+function collectQuizData() {
+ var f=this.getField("holdScoreData");
+ f.value=(oRecordOfQuizData.toSource());
+}
+% \end{macrocode}
+% \leavevmode\IndexJS{restoreQuizData()} is called when the document is opened and attempts to
+% transfer the value of \texttt{holdScoreData} back into \texttt{oRecordOfQuizData}.
+% \begin{macrocode}
+restoreQuizData.hasRestoredData=false;
+function restoreQuizData() {
+ var f=this.getField("holdScoreData");
+ try{oRecordOfQuizData=eval(f.value);}catch(e){return;}
+ for (fname in oRecordOfQuizData) {
+ f=this.getField(fname);
+ if (typeof oRecordOfQuizData[fname]=="object") {
+ // name of field is endQuiz.qzname
+ var pos=fname.indexOf(".");
+ var qzName=fname.substring(pos+1);
+ lstOfQuizzes[qzName]=eval(qzName);
+ Score=1*oRecordOfQuizData[fname][0];
+ NQuestions=1*oRecordOfQuizData[fname][1];
+ ptScore=1*oRecordOfQuizData[fname][2];
+ NPointTotal=1*oRecordOfQuizData[fname][3];
+ var h=this.getField("ScoreData."+qzName);
+ h.value=Score+";"+NQuestions+";"+ptScore+";"+NPointTotal;
+ } else f.isCorrect=oRecordOfQuizData[fname];
+ }
+}
+% \end{macrocode}
+% \leavevmode\IndexJS{IhrNameFormat()} is the format script for the \cs{nameField} command.
+% \begin{macrocode}
+function IhrNameFormat(event){
+ if(event.value!="") {
+ var value=""+event.value;
+ value = value.replace(/\s/g,"");
+ if(value==null || value.length==0) {
+ _passToQuestions=false;
+ chk4PassToQuestions.entered=false;
+ } else {
+ _passToQuestions=true;
+ chk4PassToQuestions.entered=true;
+ this.dirty=false;
+ }
+ } else {
+ chk4PassToQuestions.entered=false;
+ _passToQuestions=false;
+ }
+}
+% \end{macrocode}
+% \leavevmode\IndexJS{isAQuizUnfinishedAtSave()} is a variation on the JavaScript function
+% \texttt{isAQuizUnfinished} defined in \pkg{exerquiz}. When there is an unfinished quiz
+% and the user saves the document, this function (call by \texttt{willSave}) warns the user
+% that he will lose the answer entered into the quiz. It is too late to stop the save, there
+% is no JavaScript command for doing that.
+% \begin{macrocode}
+function isAQuizUnfinishedAtSave()
+{
+ for ( var qtfield in aQuizControl )
+ if ( aQuizControl[qtfield] == 1 )
+ {
+ eqAppAlert(\eqerrUnfinishQuizAtSave, 3);
+ return false;
+ }
+ return true;
+}
+\end{insDLJS}
+% \end{macrocode}
+% \begin{macrocode}
+\ap@restoreCats
+%</package>
+% \end{macrocode}
+\endinput
diff --git a/texmf-dist/source/latex/eq-save/eq-save.ins b/texmf-dist/source/latex/eq-save/eq-save.ins
new file mode 100644
index 00000000..6f4531a0
--- /dev/null
+++ b/texmf-dist/source/latex/eq-save/eq-save.ins
@@ -0,0 +1,60 @@
+%%
+%% This file will generate fast loadable files and documentation
+%% driver files from the doc files in this package when run through
+%% LaTeX or TeX.
+%%
+%% Copyright 1999-2016 D. P. Story
+%%
+%% This file is part of the `AcroTeX eDucation Bundle'.
+%% -------------------------------------------
+%%
+%% It may be distributed under the conditions of the LaTeX Project Public
+%% License, either version 1.2 of this license or (at your option) any
+%% later version. The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%% and version 1.2 or later is part of all distributions of LaTeX
+%% version 1999/12/01 or later.
+%%
+%% --------------- start of docstrip commands ------------------
+%%
+\def\filedate{2017/07/29}
+\def\batchfile{eq-save.ins}
+
+\input docstrip
+\ifx\generate\undefined
+ \Msg{**********************************************}
+ \Msg{*}
+ \Msg{* This installation requires docstrip}
+ \Msg{* version 2.4 or later.}
+ \Msg{*}
+ \Msg{* An older version of docstrip has been input}
+ \Msg{*}
+ \Msg{**********************************************}
+ \errhelp{Move or rename old docstrip.tex and get a newer one.}
+ \errmessage{Old docstrip in input path}
+ \batchmode
+ \csname @@end\endcsname\end
+\fi
+
+\keepsilent
+\askforoverwritefalse
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\preamble
+\endpreamble
+
+\generate
+{%
+ \file{eq-save.sty}{\from{eq-save.dtx}{copyright,package}}
+}
+
+\Msg{***************************************************************}
+\Msg{*}
+\Msg{* \space To finish the installation you have to copy the files }
+\Msg{*}
+\Msg{* \space *.sty, *.cfg and *.def into a directory searched by TeX}
+\Msg{*}
+\Msg{***************************************************************}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\endinput